mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-27 07:35:52 +00:00
build: Initial linting setup (#1560)
* sets up linting config and runs `yarn lint --fix` once, so that all changes will show up correctly in future PRs. * Note that there are still a lot of linter errors.
This commit is contained in:
committed by
Mayukha Vadari
parent
cfa014c44b
commit
6742e2048a
2
.eslintignore
Normal file
2
.eslintignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
dist
|
||||||
|
node_modules
|
||||||
99
.eslintrc.js
Normal file
99
.eslintrc.js
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
|
||||||
|
// Make ESLint compatible with TypeScript
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
// Enable linting rules with type information from our tsconfig
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: ['./tsconfig.eslint.json'],
|
||||||
|
|
||||||
|
// Allow the use of imports / ES modules
|
||||||
|
sourceType: 'module',
|
||||||
|
|
||||||
|
ecmaFeatures: {
|
||||||
|
// Enable global strict mode
|
||||||
|
impliedStrict: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Specify global variables that are predefined
|
||||||
|
env: {
|
||||||
|
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', 'plugin:mocha/recommended'],
|
||||||
|
rules: {
|
||||||
|
// Certain rippled APIs require snake_case naming
|
||||||
|
'@typescript-eslint/naming-convention': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
selector: 'interface',
|
||||||
|
format: ['PascalCase']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: 'interface',
|
||||||
|
format: ['snake_case']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// Ignore type imports when counting dependencies.
|
||||||
|
'import/max-dependencies': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
max: 5,
|
||||||
|
ignoreTypeImports: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// Removes comments and blank lines from the max-line rules
|
||||||
|
'max-lines-per-function': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
max: 50,
|
||||||
|
skipBlankLines: true,
|
||||||
|
skipComments: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'max-lines': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
max: 250,
|
||||||
|
skipBlankLines: true,
|
||||||
|
skipComments: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['test/**/*.ts'],
|
||||||
|
rules: {
|
||||||
|
// Removed the max for test files and test helper files, since tests usually need to import more things
|
||||||
|
'import/max-dependencies': 'off',
|
||||||
|
|
||||||
|
// describe blocks count as a function in Mocha tests, and can be insanely long
|
||||||
|
'max-lines-per-function': 'off',
|
||||||
|
|
||||||
|
// Tests can be very long turns off max-line count
|
||||||
|
'max-lines': 'off',
|
||||||
|
|
||||||
|
// We have lots of statements in tests
|
||||||
|
'max-statements': 'off',
|
||||||
|
|
||||||
|
// We have lots of magic numbers in tests
|
||||||
|
'no-magic-number': 'off'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['.eslintrc.js', 'jest.config.js'],
|
||||||
|
rules: {
|
||||||
|
// Removed no-commonjs requirement as eslint must be in common js format
|
||||||
|
'import/no-commonjs': 'off',
|
||||||
|
|
||||||
|
// Removed this as eslint prevents us from doing this differently
|
||||||
|
'import/unambiguous': 'off'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es6": true,
|
|
||||||
"node": true,
|
|
||||||
"mocha": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended"
|
|
||||||
],
|
|
||||||
"globals": {
|
|
||||||
"NodeJS": true
|
|
||||||
},
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2018,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
"@typescript-eslint"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"no-useless-constructor": 0,
|
|
||||||
"no-unused-vars": 0,
|
|
||||||
"no-prototype-builtins": 0,
|
|
||||||
"require-atomic-updates": 0,
|
|
||||||
"no-dupe-class-members": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
.github/workflows/nodejs.yml
vendored
29
.github/workflows/nodejs.yml
vendored
@@ -10,10 +10,27 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
unit:
|
# 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: yarn install
|
||||||
|
# - run: yarn lint
|
||||||
|
# - run: yarn build
|
||||||
|
|
||||||
|
unit:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [12.x, 14.x, 16.x]
|
node-version: [12.x, 14.x, 16.x]
|
||||||
@@ -24,10 +41,8 @@ jobs:
|
|||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- run: yarn install
|
- run: yarn install --ignore-engines
|
||||||
- run: yarn test
|
- run: yarn test
|
||||||
- run: yarn lint
|
|
||||||
- run: yarn build
|
|
||||||
|
|
||||||
integration:
|
integration:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -42,7 +57,7 @@ jobs:
|
|||||||
ports:
|
ports:
|
||||||
- 6006:6006
|
- 6006:6006
|
||||||
options:
|
options:
|
||||||
--health-cmd="wget localhost:6006 || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s
|
--health-cmd="wget localhost:6006 || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -50,7 +65,7 @@ jobs:
|
|||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- run: yarn install
|
- run: yarn install --ignore-engines
|
||||||
- run: yarn test:integration
|
- run: yarn test:integration
|
||||||
env:
|
env:
|
||||||
HOST: localhost
|
HOST: localhost
|
||||||
@@ -69,7 +84,7 @@ jobs:
|
|||||||
ports:
|
ports:
|
||||||
- 6006:6006
|
- 6006:6006
|
||||||
options:
|
options:
|
||||||
--health-cmd="wget localhost:6006 || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s
|
--health-cmd="wget localhost:6006 || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|||||||
10
.prettierrc
10
.prettierrc
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"parser": "typescript",
|
|
||||||
"printWidth": 80,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"semi": false,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"quoteProps": "consistent",
|
|
||||||
"bracketSpacing": false
|
|
||||||
}
|
|
||||||
6
.vscode/extenstions.json
vendored
Normal file
6
.vscode/extenstions.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"esbenp.prettier-vscode"
|
||||||
|
]
|
||||||
|
}
|
||||||
35
.vscode/settings.json
vendored
Normal file
35
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"[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
|
||||||
|
},
|
||||||
|
}
|
||||||
39
package.json
39
package.json
@@ -12,10 +12,6 @@
|
|||||||
"unpkg": "build/ripple-latest-min.js",
|
"unpkg": "build/ripple-latest-min.js",
|
||||||
"jsdelivr": "build/ripple-latest-min.js",
|
"jsdelivr": "build/ripple-latest-min.js",
|
||||||
"types": "dist/npm/index.d.ts",
|
"types": "dist/npm/index.d.ts",
|
||||||
"browser": {
|
|
||||||
"ws": "./dist/npm/client/wsWrapper.js",
|
|
||||||
"https-proxy-agent": false
|
|
||||||
},
|
|
||||||
"directories": {
|
"directories": {
|
||||||
"test": "test"
|
"test": "test"
|
||||||
},
|
},
|
||||||
@@ -41,8 +37,10 @@
|
|||||||
"@types/chai": "^4.2.21",
|
"@types/chai": "^4.2.21",
|
||||||
"@types/mocha": "^9.0.0",
|
"@types/mocha": "^9.0.0",
|
||||||
"@types/node": "^16.4.3",
|
"@types/node": "^16.4.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.3.3",
|
"@types/puppeteer": "5.4.4",
|
||||||
"@typescript-eslint/parser": "^2.27.0",
|
"@typescript-eslint/eslint-plugin": "^3.7.0",
|
||||||
|
"@typescript-eslint/parser": "^3.7.0",
|
||||||
|
"@xrplf/eslint-config": "^1.1.0",
|
||||||
"assert": "^2.0.0",
|
"assert": "^2.0.0",
|
||||||
"assert-diff": "^3.0.0",
|
"assert-diff": "^3.0.0",
|
||||||
"buffer": "^6.0.2",
|
"buffer": "^6.0.2",
|
||||||
@@ -50,21 +48,29 @@
|
|||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
"doctoc": "^2.0.0",
|
"doctoc": "^2.0.0",
|
||||||
"ejs": "^3.0.1",
|
"ejs": "^3.0.1",
|
||||||
"eslint": "^6.5.1",
|
"eslint": "^7.5.0",
|
||||||
|
"eslint-plugin-array-func": "^3.1.7",
|
||||||
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||||
|
"eslint-plugin-import": "^2.24.1",
|
||||||
|
"eslint-plugin-jsdoc": "^29.0.0",
|
||||||
|
"eslint-plugin-mocha": "^9.0.0",
|
||||||
|
"eslint-plugin-node": "^11.1.0",
|
||||||
|
"eslint-plugin-prettier": "^3.4.0",
|
||||||
|
"eslint-plugin-tsdoc": "^0.2.14",
|
||||||
"eventemitter2": "^6.0.0",
|
"eventemitter2": "^6.0.0",
|
||||||
"https-browserify": "^1.0.0",
|
"https-browserify": "^1.0.0",
|
||||||
"json-schema-to-markdown-table": "^0.4.0",
|
"json-schema-to-markdown-table": "^0.4.0",
|
||||||
"mocha": "^9",
|
"mocha": "^9",
|
||||||
"nyc": "^15",
|
"nyc": "^15",
|
||||||
"path-browserify": "1.0.1",
|
"path-browserify": "1.0.1",
|
||||||
"prettier": "^2.0.5",
|
"prettier": "^2.3.2",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"puppeteer": "10.2.0",
|
"puppeteer": "10.2.0",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"stream-http": "3.2.0",
|
"stream-http": "3.2.0",
|
||||||
"ts-loader": "^9.2.5",
|
"ts-loader": "^9.2.5",
|
||||||
"ts-node": "^10.1.0",
|
"ts-node": "^10.1.0",
|
||||||
"typescript": "^3.9.9",
|
"typescript": "^3.9.10",
|
||||||
"url": "^0.11.0",
|
"url": "^0.11.0",
|
||||||
"webpack": "^5.6.0",
|
"webpack": "^5.6.0",
|
||||||
"webpack-bundle-analyzer": "^4.1.0",
|
"webpack-bundle-analyzer": "^4.1.0",
|
||||||
@@ -72,21 +78,22 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:schemas": "mkdir -p dist/npm/common && cp -r src/common/schemas dist/npm/common/",
|
"build:schemas": "mkdir -p dist/npm/common && cp -r src/common/schemas dist/npm/common/",
|
||||||
"build:lib": "tsc --build",
|
"build:snippets": "tsc --build ./snippets/tsconfig.json",
|
||||||
|
"build:lib": "tsc --build tsconfig.build.json",
|
||||||
"build:web": "webpack",
|
"build:web": "webpack",
|
||||||
"build": "yarn build:schemas && yarn build:lib && yarn build:web",
|
"build": "yarn build:schemas && yarn build:lib && yarn build:snippets && yarn build:web",
|
||||||
"analyze": "yarn build:web --analyze",
|
"analyze": "yarn build:web --analyze",
|
||||||
"watch": "yarn build:lib --watch",
|
"watch": "yarn build:lib --watch",
|
||||||
"clean": "rm -rf dist/npm",
|
"clean": "rm -rf dist",
|
||||||
"doctoc": "doctoc docs/index.md --title '# RippleAPI Reference' --github --maxlevel 2",
|
"doctoc": "doctoc docs/index.md --title '# RippleAPI Reference' --github --maxlevel 2",
|
||||||
"docgen": "node --harmony scripts/build_docs.js",
|
"docgen": "node --harmony scripts/build_docs.js",
|
||||||
"prepublish": "yarn clean && yarn build",
|
"prepublish": "yarn clean && yarn build",
|
||||||
"test": "TS_NODE_PROJECT=src/tsconfig.json nyc mocha --config=test/.mocharc.json --exit",
|
"test": "nyc mocha --config=test/.mocharc.json --exit",
|
||||||
"test:integration": "TS_NODE_PROJECT=src/tsconfig.json nyc mocha ./test/integration/*.ts",
|
"test:integration": "TS_NODE_PROJECT=tsconfig.build.json nyc mocha ./test/integration/*.ts",
|
||||||
"test:browser": "TS_NODE_PROJECT=src/tsconfig.json nyc mocha ./test/browser/*.ts",
|
"test:browser": "TS_NODE_PROJECT=tsconfig.build.json nyc mocha ./test/browser/*.ts",
|
||||||
"test:watch": "TS_NODE_PROJECT=src/tsconfig.json mocha --config=test/.mocharc.json --watch --reporter dot",
|
"test:watch": "TS_NODE_PROJECT=src/tsconfig.json mocha --config=test/.mocharc.json --watch --reporter dot",
|
||||||
"format": "prettier --write '{src,test}/**/*.ts'",
|
"format": "prettier --write '{src,test}/**/*.ts'",
|
||||||
"lint": "eslint 'src/**/*.ts' 'test/*.{ts,js}'",
|
"lint": "eslint . --ext .ts --max-warnings 0",
|
||||||
"perf": "./scripts/perf_test.sh",
|
"perf": "./scripts/perf_test.sh",
|
||||||
"compile:snippets": "tsc -p snippets/tsconfig.json",
|
"compile:snippets": "tsc -p snippets/tsconfig.json",
|
||||||
"start:snippet": "npm run compile:snippets && node ./snippets/dist/start.js",
|
"start:snippet": "npm run compile:snippets && node ./snippets/dist/start.js",
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import * as codec from 'ripple-binary-codec'
|
// import * as codec from 'ripple-binary-codec'
|
||||||
|
|
||||||
const original = codec.decode('12000022800200002400000001201B00EF81E661EC6386F26FC0FFFF0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461968400000000000000C6940000000000000646AD3504529A0465E2E0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D1664619732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402200A693FB5CA6B21250EBDFD8CFF526EE0DF7C9E4E31EB0660692E75E6A93BF5F802203CC39463DDA21386898CA31E18AD1A6828647D65741DD637BAD71BC83E29DB9481145E7B112523F68D2F5E879DB4EAC51C6698A693048314CA6EDC7A28252DAEA6F2045B24F4D7C333E146170112300000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461900')
|
// const original = codec.decode(
|
||||||
|
// '12000022800200002400000001201B00EF81E661EC6386F26FC0FFFF0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461968400000000000000C6940000000000000646AD3504529A0465E2E0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D1664619732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402200A693FB5CA6B21250EBDFD8CFF526EE0DF7C9E4E31EB0660692E75E6A93BF5F802203CC39463DDA21386898CA31E18AD1A6828647D65741DD637BAD71BC83E29DB9481145E7B112523F68D2F5E879DB4EAC51C6698A693048314CA6EDC7A28252DAEA6F2045B24F4D7C333E146170112300000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461900'
|
||||||
|
// )
|
||||||
|
|
||||||
const test = codec.decode('12000022800200002400000017201B008694F261EC6386F26FC0FFFF0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461968400000000000000C6940000000000000646AD3504529A0465E2E0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D1664619732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D874473045022100D8B57E8E06EAE27B1343AF8CAD3F501E18260CCF8BCED08066074106F0F191A3022058FEA6CE9E7FA69D1244C3A70F18983CC2DAF0B10CBB86A6677CF2A5D2B8A68081145E7B112523F68D2F5E879DB4EAC51C6698A693048314CA6EDC7A28252DAEA6F2045B24F4D7C333E146170112300000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461900')
|
// const test = codec.decode(
|
||||||
|
// '12000022800200002400000017201B008694F261EC6386F26FC0FFFF0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461968400000000000000C6940000000000000646AD3504529A0465E2E0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D1664619732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D874473045022100D8B57E8E06EAE27B1343AF8CAD3F501E18260CCF8BCED08066074106F0F191A3022058FEA6CE9E7FA69D1244C3A70F18983CC2DAF0B10CBB86A6677CF2A5D2B8A68081145E7B112523F68D2F5E879DB4EAC51C6698A693048314CA6EDC7A28252DAEA6F2045B24F4D7C333E146170112300000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461900'
|
||||||
|
// )
|
||||||
|
|
||||||
console.log('original:', JSON.stringify(original))
|
// console.log('original:', JSON.stringify(original))
|
||||||
|
|
||||||
console.log('test:', JSON.stringify(test))
|
// console.log('test:', JSON.stringify(test))
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
import {Client} from '../../dist/npm'
|
// import {Client} from '../../dist/npm'
|
||||||
import { TransactionMetadata } from '../../src/models/common/transaction'
|
// import {TransactionMetadata} from '../../src/models/common/transaction'
|
||||||
|
|
||||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
// const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||||
|
|
||||||
getTransaction()
|
// getTransaction()
|
||||||
|
|
||||||
async function getTransaction() {
|
// async function getTransaction() {
|
||||||
await client.connect()
|
// await client.connect()
|
||||||
const ledger = await client.request({command: 'ledger', transactions: true})
|
// const ledger = await client.request({command: 'ledger', transactions: true})
|
||||||
console.log(ledger)
|
// console.log(ledger)
|
||||||
const tx = await client.request({
|
// const tx = await client.request({
|
||||||
command: 'tx',
|
// command: 'tx',
|
||||||
transaction: ledger.result.ledger.transactions[0] as string
|
// transaction: ledger.result.ledger.transactions[0] as string
|
||||||
})
|
// })
|
||||||
console.log(tx)
|
// console.log(tx)
|
||||||
console.log('deliveredAmount:', (tx.result.meta as TransactionMetadata).DeliveredAmount)
|
// console.log(
|
||||||
process.exit(0)
|
// 'deliveredAmount:',
|
||||||
}
|
// (tx.result.meta as TransactionMetadata).DeliveredAmount
|
||||||
|
// )
|
||||||
|
// process.exit(0)
|
||||||
|
// }
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
import {Client} from '../../dist/npm'
|
// import {Client} from '../../dist/npm'
|
||||||
import { AccountFlags } from '../../dist/npm/common/constants'
|
// import {AccountFlags} from '../../dist/npm/common/constants'
|
||||||
|
|
||||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
// const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||||
|
|
||||||
parseAccountFlags()
|
// parseAccountFlags()
|
||||||
|
|
||||||
async function parseAccountFlags() {
|
// async function parseAccountFlags() {
|
||||||
await client.connect()
|
// await client.connect()
|
||||||
const account_info = await client.request({command: 'account_info', account: 'rKsdkGhyZH6b2Zzd5hNnEqSv2wpznn4n6N'})
|
// const account_info = await client.request({
|
||||||
const flags = account_info.result.account_data.Flags
|
// command: 'account_info',
|
||||||
for (const flagName in AccountFlags) {
|
// account: 'rKsdkGhyZH6b2Zzd5hNnEqSv2wpznn4n6N'
|
||||||
if (flags & AccountFlags[flagName]) {
|
// })
|
||||||
console.log(`${flagName} enabled`)
|
// const flags = account_info.result.account_data.Flags
|
||||||
}
|
// for (const flagName in AccountFlags) {
|
||||||
}
|
// if (flags & AccountFlags[flagName]) {
|
||||||
process.exit(0)
|
// console.log(`${flagName} enabled`)
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
// process.exit(0)
|
||||||
|
// }
|
||||||
|
|||||||
@@ -1,47 +1,53 @@
|
|||||||
import {Client} from '../../dist/npm'
|
// import {Client} from '../../dist/npm'
|
||||||
|
|
||||||
const client = new Client(
|
// const client = new Client(
|
||||||
// 'wss://s.altnet.rippletest.net:51233'
|
// // 'wss://s.altnet.rippletest.net:51233'
|
||||||
// 'ws://35.158.96.209:51233'
|
// // 'ws://35.158.96.209:51233'
|
||||||
'ws://34.210.87.206:51233'
|
// 'ws://34.210.87.206:51233'
|
||||||
)
|
// )
|
||||||
|
|
||||||
sign()
|
// sign()
|
||||||
|
|
||||||
async function sign() {
|
// async function sign() {
|
||||||
await client.connect()
|
// await client.connect()
|
||||||
const pathfind: any = {
|
// const pathfind: any = {
|
||||||
source: {
|
// source: {
|
||||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
// address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||||
amount: {
|
// amount: {
|
||||||
currency: 'drops',
|
// currency: 'drops',
|
||||||
value: '100'
|
// value: '100'
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
destination: {
|
// destination: {
|
||||||
address: 'rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj',
|
// address: 'rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj',
|
||||||
amount: {
|
// amount: {
|
||||||
currency: 'USD',
|
// currency: 'USD',
|
||||||
counterparty: 'rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc'
|
// counterparty: 'rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc'
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
await client.getPaths(pathfind).then(async (data) => {
|
// await client
|
||||||
console.log('paths:', JSON.stringify(data))
|
// .getPaths(pathfind)
|
||||||
const fakeSecret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
// .then(async (data) => {
|
||||||
|
// console.log('paths:', JSON.stringify(data))
|
||||||
|
// const fakeSecret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||||
|
|
||||||
pathfind.paths = data[0].paths
|
// pathfind.paths = data[0].paths
|
||||||
pathfind.destination = data[0].destination
|
// pathfind.destination = data[0].destination
|
||||||
await client.preparePayment('r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59', pathfind).then(ret => {
|
// await client
|
||||||
const signed = client.sign(ret.txJSON, fakeSecret)
|
// .preparePayment('r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59', pathfind)
|
||||||
console.log('signed:', signed)
|
// .then((ret) => {
|
||||||
}).catch(err => {
|
// const signed = client.sign(ret.txJSON, fakeSecret)
|
||||||
console.log('ERR 1:', JSON.stringify(err))
|
// console.log('signed:', signed)
|
||||||
})
|
// })
|
||||||
}).catch(err => {
|
// .catch((err) => {
|
||||||
console.log('ERR 2:', err)
|
// console.log('ERR 1:', JSON.stringify(err))
|
||||||
})
|
// })
|
||||||
|
// })
|
||||||
|
// .catch((err) => {
|
||||||
|
// console.log('ERR 2:', err)
|
||||||
|
// })
|
||||||
|
|
||||||
client.disconnect()
|
// client.disconnect()
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -1,201 +1,215 @@
|
|||||||
import {
|
// import https = require('https')
|
||||||
Client,
|
|
||||||
AccountInfoResponse,
|
|
||||||
LedgerClosedEvent
|
|
||||||
} from '../../dist/npm'
|
|
||||||
import https = require('https')
|
|
||||||
|
|
||||||
/**
|
// import {Client, AccountInfoResponse, LedgerClosedEvent} from '../../dist/npm'
|
||||||
* When implementing Reliable Transaction Submission, there are many potential solutions, each with different trade-offs. The main decision points are:
|
|
||||||
* 1) Transaction preparation:
|
|
||||||
* - How do we decide which account sequence and LastLedgerSequence numbers to use?
|
|
||||||
* (To prevent unintentional duplicate transactions, an {account, account_sequence} pair can be used as a transaction's idempotency key)
|
|
||||||
* - How do we decide how much to pay for the transaction fee? (If our transactions have been failing due to low fee, we should consider increasing this value)
|
|
||||||
* 2) Transaction status retrieval. Options include:
|
|
||||||
* - Poll for transaction status:
|
|
||||||
* - On a regular interval (e.g. every 3-5 seconds), or
|
|
||||||
* - When a new validated ledger is detected
|
|
||||||
* + (To accommodate an edge case in transaction retrieval, check the sending account's Sequence number to confirm that it has the expected value;
|
|
||||||
* alternatively, wait until a few additional ledgers have been validated before deciding that a transaction has definitively not been included in a validated ledger)
|
|
||||||
* - Listen for transaction status: scan all validated transactions to see if our transactions are among them
|
|
||||||
* 3) What do we do when a transaction fails? It is possible to implement retry logic, but caution is advised. Note that there are a few ways for a transaction to fail:
|
|
||||||
* A) `tec`: The transaction was included in a ledger but only claimed the transaction fee
|
|
||||||
* B) `tesSUCCESS` but unexpected result: The transaction was successful but did not have the expected result. This generally does not occur for XRP-to-XRP payments
|
|
||||||
* C) The transaction was not, and never will be, included in a validated ledger [3C]
|
|
||||||
*
|
|
||||||
* References:
|
|
||||||
* - https://xrpl.org/reliable-transaction-submission.html
|
|
||||||
* - https://xrpl.org/send-xrp.html
|
|
||||||
* - https://xrpl.org/look-up-transaction-results.html
|
|
||||||
* - https://xrpl.org/get-started-with-rippleapi-for-javascript.html
|
|
||||||
* - https://xrpl.org/monitor-incoming-payments-with-websocket.html
|
|
||||||
*
|
|
||||||
* For the implementation in this example, we have made the following decisions:
|
|
||||||
* 1) The script will choose the account sequence and LastLedgerSequence numbers automatically. We allow ripple-lib to choose the fee.
|
|
||||||
* Payments are defined upfront, and idempotency is not needed. If the script is run a second time, duplicate payments will result.
|
|
||||||
* 2) We will listen for notification that a new validated ledger has been found, and poll for transaction status at that time.
|
|
||||||
* Futhermore, as a precaution, we will wait until the server is 3 ledgers past the transaction's LastLedgerSequence
|
|
||||||
* (with the transaction nowhere to be seen) before deciding that it has definitively failed per [3C]
|
|
||||||
* 3) Transactions will not be automatically retried. Transactions are limited to XRP-to-XRP payments and cannot "succeed" in an unexpected way.
|
|
||||||
*/
|
|
||||||
reliableTransactionSubmissionExample()
|
|
||||||
|
|
||||||
async function reliableTransactionSubmissionExample() {
|
// /**
|
||||||
/**
|
// * When implementing Reliable Transaction Submission, there are many potential solutions, each with different trade-offs. The main decision points are:
|
||||||
* Array of payments to execute.
|
// * 1) Transaction preparation:
|
||||||
*
|
// * - How do we decide which account sequence and LastLedgerSequence numbers to use?
|
||||||
* For brevity, these are XRP-to-XRP payments, taking a source, destination, and an amount in drops.
|
// * (To prevent unintentional duplicate transactions, an {account, account_sequence} pair can be used as a transaction's idempotency key)
|
||||||
*
|
// * - How do we decide how much to pay for the transaction fee? (If our transactions have been failing due to low fee, we should consider increasing this value)
|
||||||
* The script will attempt to make all of these payments as quickly as possible, and report the final status of each. Transactions that fail are NOT retried.
|
// * 2) Transaction status retrieval. Options include:
|
||||||
*/
|
// * - Poll for transaction status:
|
||||||
const payments = []
|
// * - On a regular interval (e.g. Every 3-5 seconds), or
|
||||||
|
// * - When a new validated ledger is detected
|
||||||
|
// * + (To accommodate an edge case in transaction retrieval, check the sending account's Sequence number to confirm that it has the expected value;
|
||||||
|
// * alternatively, wait until a few additional ledgers have been validated before deciding that a transaction has definitively not been included in a validated ledger)
|
||||||
|
// * - Listen for transaction status: scan all validated transactions to see if our transactions are among them
|
||||||
|
// * 3) What do we do when a transaction fails? It is possible to implement retry logic, but caution is advised. Note that there are a few ways for a transaction to fail:
|
||||||
|
// * A) `tec`: The transaction was included in a ledger but only claimed the transaction fee
|
||||||
|
// * B) `tesSUCCESS` but unexpected result: The transaction was successful but did not have the expected result. This generally does not occur for XRP-to-XRP payments
|
||||||
|
// * C) The transaction was not, and never will be, included in a validated ledger [3C].
|
||||||
|
// *
|
||||||
|
// * References:
|
||||||
|
// * - https://xrpl.org/reliable-transaction-submission.html
|
||||||
|
// * - https://xrpl.org/send-xrp.html
|
||||||
|
// * - https://xrpl.org/look-up-transaction-results.html
|
||||||
|
// * - https://xrpl.org/get-started-with-rippleapi-for-javascript.html
|
||||||
|
// * - https://xrpl.org/monitor-incoming-payments-with-websocket.html.
|
||||||
|
// *
|
||||||
|
// * For the implementation in this example, we have made the following decisions:
|
||||||
|
// * 1) The script will choose the account sequence and LastLedgerSequence numbers automatically. We allow ripple-lib to choose the fee.
|
||||||
|
// * Payments are defined upfront, and idempotency is not needed. If the script is run a second time, duplicate payments will result.
|
||||||
|
// * 2) We will listen for notification that a new validated ledger has been found, and poll for transaction status at that time.
|
||||||
|
// * Futhermore, as a precaution, we will wait until the server is 3 ledgers past the transaction's LastLedgerSequence
|
||||||
|
// * (with the transaction nowhere to be seen) before deciding that it has definitively failed per [3C]
|
||||||
|
// * 3) Transactions will not be automatically retried. Transactions are limited to XRP-to-XRP payments and cannot "succeed" in an unexpected way.
|
||||||
|
// */
|
||||||
|
// reliableTransactionSubmissionExample()
|
||||||
|
|
||||||
const sourceAccount = (await generateTestnetAccount()).account
|
// async function reliableTransactionSubmissionExample() {
|
||||||
console.log(`Generated new Testnet account: ${sourceAccount.classicAddress}/${sourceAccount.secret}`)
|
// /**
|
||||||
// Send amounts from 1 drop to 10 drops
|
// * Array of payments to execute.
|
||||||
for (let i = 1; i <= 10; i++) {
|
// *
|
||||||
payments.push({
|
// * For brevity, these are XRP-to-XRP payments, taking a source, destination, and an amount in drops.
|
||||||
source: sourceAccount,
|
// *
|
||||||
destination: 'rhsoCozhUxwcyQgzFi1FVRoMVQgk7cZd4L', // Random Testnet destination
|
// * The script will attempt to make all of these payments as quickly as possible, and report the final status of each. Transactions that fail are NOT retried.
|
||||||
amount_drops: i.toString(),
|
// */
|
||||||
})
|
// const payments = []
|
||||||
}
|
|
||||||
const results = await performPayments(payments)
|
|
||||||
console.log(JSON.stringify(results, null, 2))
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function performPayments(payments) {
|
// const sourceAccount = (await generateTestnetAccount()).account
|
||||||
const finalResults = []
|
// console.log(
|
||||||
const txFinalizedPromises = []
|
// `Generated new Testnet account: ${sourceAccount.classicAddress}/${sourceAccount.secret}`
|
||||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
// )
|
||||||
await client.connect()
|
// // Send amounts from 1 drop to 10 drops
|
||||||
|
// for (let i = 1; i <= 10; i++) {
|
||||||
|
// payments.push({
|
||||||
|
// source: sourceAccount,
|
||||||
|
// destination: 'rhsoCozhUxwcyQgzFi1FVRoMVQgk7cZd4L', // Random Testnet destination
|
||||||
|
// amount_drops: i.toString()
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// const results = await performPayments(payments)
|
||||||
|
// console.log(JSON.stringify(results, null, 2))
|
||||||
|
// process.exit(0)
|
||||||
|
// }
|
||||||
|
|
||||||
for (let i = 0; i < payments.length; i++) {
|
// async function performPayments(payments) {
|
||||||
const payment = payments[i]
|
// const finalResults = []
|
||||||
const account_info: AccountInfoResponse = await client.request({
|
// const txFinalizedPromises = []
|
||||||
command: 'account_info',
|
// const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||||
account: payment.source.classicAddress,
|
// await client.connect()
|
||||||
ledger_index: 'current'})
|
|
||||||
const sequence = account_info.result.account_data.Sequence
|
|
||||||
const preparedPayment = await client.preparePayment(payment.source.classicAddress, {
|
|
||||||
source: {
|
|
||||||
address: payment.source.classicAddress,
|
|
||||||
amount: {
|
|
||||||
value: payment.amount_drops,
|
|
||||||
currency: 'drops'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
destination: {
|
|
||||||
address: payment.destination,
|
|
||||||
minAmount: {
|
|
||||||
value: payment.amount_drops,
|
|
||||||
currency: 'drops'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
sequence
|
|
||||||
})
|
|
||||||
const signed = client.sign(preparedPayment.txJSON, payment.source.secret)
|
|
||||||
finalResults.push({
|
|
||||||
id: signed.id
|
|
||||||
})
|
|
||||||
const response = await client.request({command: 'submit', tx_blob: signed.signedTransaction})
|
|
||||||
|
|
||||||
// Most of the time we'll get 'tesSUCCESS' or (after many submissions) 'terQUEUED'
|
// for (let i = 0; i < payments.length; i++) {
|
||||||
console.log(`tx ${i} - tentative: ${response.result.engine_result}`)
|
// const payment = payments[i]
|
||||||
|
// const account_info: AccountInfoResponse = await client.request({
|
||||||
|
// command: 'account_info',
|
||||||
|
// account: payment.source.classicAddress,
|
||||||
|
// ledger_index: 'current'
|
||||||
|
// })
|
||||||
|
// const sequence = account_info.result.account_data.Sequence
|
||||||
|
// const preparedPayment = await client.preparePayment(
|
||||||
|
// payment.source.classicAddress,
|
||||||
|
// {
|
||||||
|
// source: {
|
||||||
|
// address: payment.source.classicAddress,
|
||||||
|
// amount: {
|
||||||
|
// value: payment.amount_drops,
|
||||||
|
// currency: 'drops'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// destination: {
|
||||||
|
// address: payment.destination,
|
||||||
|
// minAmount: {
|
||||||
|
// value: payment.amount_drops,
|
||||||
|
// currency: 'drops'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// sequence
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// const signed = client.sign(preparedPayment.txJSON, payment.source.secret)
|
||||||
|
// finalResults.push({
|
||||||
|
// id: signed.id
|
||||||
|
// })
|
||||||
|
// const response = await client.request({
|
||||||
|
// command: 'submit',
|
||||||
|
// tx_blob: signed.signedTransaction
|
||||||
|
// })
|
||||||
|
|
||||||
const txFinalizedPromise = new Promise<void>((resolve) => {
|
// // Most of the time we'll get 'tesSUCCESS' or (after many submissions) 'terQUEUED'
|
||||||
const ledgerClosedCallback = async (event: LedgerClosedEvent) => {
|
// console.log(`tx ${i} - tentative: ${response.result.engine_result}`)
|
||||||
let status
|
|
||||||
try {
|
|
||||||
status = await client.request({command: 'tx', transaction: signed.id})
|
|
||||||
} catch (e) {
|
|
||||||
// Typical error when the tx hasn't been validated yet:
|
|
||||||
if (e.name !== 'MissingLedgerHistoryError') {
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.ledger_index > preparedPayment.instructions.maxLedgerVersion + 3) {
|
// const txFinalizedPromise = new Promise<void>((resolve) => {
|
||||||
// Assumptions:
|
// const ledgerClosedCallback = async (event: LedgerClosedEvent) => {
|
||||||
// - We are still connected to the same rippled server
|
// let status
|
||||||
// - No ledger gaps occurred
|
// try {
|
||||||
// - All ledgers between the time we submitted the tx and now have been checked for the tx
|
// status = await client.request({command: 'tx', transaction: signed.id})
|
||||||
status = {
|
// } catch (e) {
|
||||||
finalResult: 'Transaction was not, and never will be, included in a validated ledger'
|
// // Typical error when the tx hasn't been validated yet:
|
||||||
}
|
// if (e.name !== 'MissingLedgerHistoryError') {
|
||||||
} else {
|
// console.log(e)
|
||||||
// Check again later:
|
// }
|
||||||
client.connection.once('ledgerClosed', ledgerClosedCallback)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let j = 0; j < finalResults.length; j++) {
|
// if (
|
||||||
if (finalResults[j].id === signed.id) {
|
// event.ledger_index >
|
||||||
finalResults[j].result = status.address ? {
|
// preparedPayment.instructions.maxLedgerVersion + 3
|
||||||
source: status.address,
|
// ) {
|
||||||
destination: status.specification.destination.address,
|
// // Assumptions:
|
||||||
deliveredAmount: status.outcome.deliveredAmount,
|
// // - We are still connected to the same rippled server
|
||||||
result: status.outcome.result,
|
// // - No ledger gaps occurred
|
||||||
timestamp: status.outcome.timestamp,
|
// // - All ledgers between the time we submitted the tx and now have been checked for the tx
|
||||||
ledgerVersion: status.outcome.ledgerVersion
|
// status = {
|
||||||
} : status
|
// finalResult:
|
||||||
process.stdout.write('.')
|
// 'Transaction was not, and never will be, included in a validated ledger'
|
||||||
return resolve()
|
// }
|
||||||
}
|
// } else {
|
||||||
}
|
// // Check again later:
|
||||||
}
|
// client.connection.once('ledgerClosed', ledgerClosedCallback)
|
||||||
client.connection.once('ledgerClosed', ledgerClosedCallback)
|
// return
|
||||||
})
|
// }
|
||||||
txFinalizedPromises.push(txFinalizedPromise)
|
// }
|
||||||
}
|
|
||||||
await Promise.all(txFinalizedPromises)
|
|
||||||
return finalResults
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// for (let j = 0; j < finalResults.length; j++) {
|
||||||
* Generate a new Testnet account by requesting one from the faucet
|
// if (finalResults[j].id === signed.id) {
|
||||||
*/
|
// finalResults[j].result = status.address
|
||||||
async function generateTestnetAccount(): Promise<{
|
// ? {
|
||||||
account: {
|
// source: status.address,
|
||||||
xAddress: string,
|
// destination: status.specification.destination.address,
|
||||||
classicAddress, string,
|
// deliveredAmount: status.outcome.deliveredAmount,
|
||||||
secret: string
|
// result: status.outcome.result,
|
||||||
},
|
// timestamp: status.outcome.timestamp,
|
||||||
balance: number
|
// ledgerVersion: status.outcome.ledgerVersion
|
||||||
}> {
|
// }
|
||||||
const options = {
|
// : status
|
||||||
hostname: 'faucet.altnet.rippletest.net',
|
// process.stdout.write('.')
|
||||||
port: 443,
|
// return resolve()
|
||||||
path: '/accounts',
|
// }
|
||||||
method: 'POST'
|
// }
|
||||||
}
|
// }
|
||||||
return new Promise((resolve, reject) => {
|
// client.connection.once('ledgerClosed', ledgerClosedCallback)
|
||||||
const request = https.request(options, response => {
|
// })
|
||||||
const chunks = []
|
// txFinalizedPromises.push(txFinalizedPromise)
|
||||||
response.on('data', d => {
|
// }
|
||||||
chunks.push(d)
|
// await Promise.all(txFinalizedPromises)
|
||||||
})
|
// return finalResults
|
||||||
response.on('end', () => {
|
// }
|
||||||
const body = Buffer.concat(chunks).toString()
|
|
||||||
|
|
||||||
// "application/json; charset=utf-8"
|
// /**
|
||||||
if (response.headers['content-type'].startsWith('application/json')) {
|
// * Generate a new Testnet account by requesting one from the faucet.
|
||||||
resolve(JSON.parse(body))
|
// */
|
||||||
} else {
|
// async function generateTestnetAccount(): Promise<{
|
||||||
reject({
|
// account: {
|
||||||
statusCode: response.statusCode,
|
// xAddress: string
|
||||||
contentType: response.headers['content-type'],
|
// classicAddress
|
||||||
body
|
// string
|
||||||
})
|
// secret: string
|
||||||
}
|
// }
|
||||||
})
|
// balance: number
|
||||||
})
|
// }> {
|
||||||
request.on('error', error => {
|
// const options = {
|
||||||
console.error(error)
|
// hostname: 'faucet.altnet.rippletest.net',
|
||||||
reject(error)
|
// port: 443,
|
||||||
})
|
// path: '/accounts',
|
||||||
request.end()
|
// method: 'POST'
|
||||||
})
|
// }
|
||||||
}
|
// return new Promise((resolve, reject) => {
|
||||||
|
// const request = https.request(options, (response) => {
|
||||||
|
// const chunks = []
|
||||||
|
// response.on('data', (d) => {
|
||||||
|
// chunks.push(d)
|
||||||
|
// })
|
||||||
|
// response.on('end', () => {
|
||||||
|
// const body = Buffer.concat(chunks).toString()
|
||||||
|
|
||||||
|
// // "application/json; charset=utf-8"
|
||||||
|
// if (response.headers['content-type'].startsWith('application/json')) {
|
||||||
|
// resolve(JSON.parse(body))
|
||||||
|
// } else {
|
||||||
|
// reject({
|
||||||
|
// statusCode: response.statusCode,
|
||||||
|
// contentType: response.headers['content-type'],
|
||||||
|
// body
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// request.on('error', (error) => {
|
||||||
|
// console.error(error)
|
||||||
|
// reject(error)
|
||||||
|
// })
|
||||||
|
// request.end()
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig-base",
|
"extends": "../tsconfig.build.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"rootDir": "./src"
|
|
||||||
},
|
},
|
||||||
"references": [
|
|
||||||
{ "path": "../src" }
|
|
||||||
],
|
|
||||||
"include": [
|
"include": [
|
||||||
"./src/**/*.ts"
|
"./src/**/*.ts"
|
||||||
]
|
]
|
||||||
|
|||||||
120
src/Wallet.ts
120
src/Wallet.ts
@@ -1,12 +1,13 @@
|
|||||||
import {fromSeed} from 'bip32'
|
import { fromSeed } from "bip32";
|
||||||
import {mnemonicToSeedSync} from 'bip39'
|
import { mnemonicToSeedSync } from "bip39";
|
||||||
import {decode, encodeForSigning} from 'ripple-binary-codec'
|
import { decode, encodeForSigning } from "ripple-binary-codec";
|
||||||
import {deriveKeypair, generateSeed, verify} from 'ripple-keypairs'
|
import { deriveKeypair, generateSeed, verify } from "ripple-keypairs";
|
||||||
import ECDSA from './common/ecdsa'
|
|
||||||
import {SignedTransaction} from './common/types/objects'
|
import ECDSA from "./common/ecdsa";
|
||||||
import {signOffline} from './transaction/sign'
|
import { ValidationError } from "./common/errors";
|
||||||
import {SignOptions} from './transaction/types'
|
import { SignedTransaction } from "./common/types/objects";
|
||||||
import {ValidationError} from './common/errors'
|
import { signOffline } from "./transaction/sign";
|
||||||
|
import { SignOptions } from "./transaction/types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility for deriving a wallet composed of a keypair (publicKey/privateKey).
|
* A utility for deriving a wallet composed of a keypair (publicKey/privateKey).
|
||||||
@@ -14,53 +15,61 @@ import {ValidationError} from './common/errors'
|
|||||||
* It provides functionality to sign/verify transactions offline.
|
* It provides functionality to sign/verify transactions offline.
|
||||||
*/
|
*/
|
||||||
class Wallet {
|
class Wallet {
|
||||||
readonly publicKey: string
|
readonly publicKey: string;
|
||||||
readonly privateKey: string
|
readonly privateKey: string;
|
||||||
private static readonly defaultAlgorithm: ECDSA = ECDSA.ed25519
|
private static readonly defaultAlgorithm: ECDSA = ECDSA.ed25519;
|
||||||
private static readonly defaultDerivationPath: string = "m/44'/144'/0'/0/0"
|
private static readonly defaultDerivationPath: string = "m/44'/144'/0'/0/0";
|
||||||
|
|
||||||
constructor(publicKey: string, privateKey: string) {
|
constructor(publicKey: string, privateKey: string) {
|
||||||
this.publicKey = publicKey
|
this.publicKey = publicKey;
|
||||||
this.privateKey = privateKey
|
this.privateKey = privateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives a wallet from a seed.
|
* Derives a wallet from a seed.
|
||||||
* @param {string} seed A string used to generate a keypair (publicKey/privateKey) to derive a wallet.
|
*
|
||||||
* @param {ECDSA} algorithm The digital signature algorithm to generate an address for.
|
* @param seed - A string used to generate a keypair (publicKey/privateKey) to derive a wallet.
|
||||||
* @returns {Wallet} A Wallet derived from a seed.
|
* @param algorithm - The digital signature algorithm to generate an address for.
|
||||||
|
* @returns A Wallet derived from a seed.
|
||||||
*/
|
*/
|
||||||
static fromSeed(seed: string, algorithm: ECDSA = Wallet.defaultAlgorithm): Wallet {
|
static fromSeed(
|
||||||
return Wallet.deriveWallet(seed, algorithm)
|
seed: string,
|
||||||
|
algorithm: ECDSA = Wallet.defaultAlgorithm
|
||||||
|
): Wallet {
|
||||||
|
return Wallet.deriveWallet(seed, algorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives a wallet from a mnemonic.
|
* Derives a wallet from a mnemonic.
|
||||||
* @param {string} mnemonic A string consisting of words (whitespace delimited) used to derive a wallet.
|
*
|
||||||
* @param {string} derivationPath The path to derive a keypair (publicKey/privateKey) from a seed (that was converted from a mnemonic).
|
* @param mnemonic - A string consisting of words (whitespace delimited) used to derive a wallet.
|
||||||
* @returns {Wallet} A Wallet derived from a mnemonic.
|
* @param derivationPath - The path to derive a keypair (publicKey/privateKey) from a seed (that was converted from a mnemonic).
|
||||||
|
* @returns A Wallet derived from a mnemonic.
|
||||||
*/
|
*/
|
||||||
static fromMnemonic(
|
static fromMnemonic(
|
||||||
mnemonic: string,
|
mnemonic: string,
|
||||||
derivationPath: string = Wallet.defaultDerivationPath
|
derivationPath: string = Wallet.defaultDerivationPath
|
||||||
): Wallet {
|
): Wallet {
|
||||||
const seed = mnemonicToSeedSync(mnemonic)
|
const seed = mnemonicToSeedSync(mnemonic);
|
||||||
const masterNode = fromSeed(seed)
|
const masterNode = fromSeed(seed);
|
||||||
const node = masterNode.derivePath(derivationPath)
|
const node = masterNode.derivePath(derivationPath);
|
||||||
if (node.privateKey === undefined) {
|
if (node.privateKey === undefined) {
|
||||||
throw new ValidationError('Unable to derive privateKey from mnemonic input')
|
throw new ValidationError(
|
||||||
|
"Unable to derive privateKey from mnemonic input"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const publicKey = Wallet.hexFromBuffer(node.publicKey)
|
const publicKey = Wallet.hexFromBuffer(node.publicKey);
|
||||||
const privateKey = Wallet.hexFromBuffer(node.privateKey)
|
const privateKey = Wallet.hexFromBuffer(node.privateKey);
|
||||||
return new Wallet(publicKey, `00${privateKey}`)
|
return new Wallet(publicKey, `00${privateKey}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives a wallet from an entropy (array of random numbers).
|
* Derives a wallet from an entropy (array of random numbers).
|
||||||
* @param {Uint8Array | number[]} entropy An array of random numbers to generate a seed used to derive a wallet.
|
*
|
||||||
* @param {ECDSA} algorithm The digital signature algorithm to generate an address for.
|
* @param entropy - An array of random numbers to generate a seed used to derive a wallet.
|
||||||
* @returns {Wallet} A Wallet derived from an entropy.
|
* @param algorithm - The digital signature algorithm to generate an address for.
|
||||||
|
* @returns A Wallet derived from an entropy.
|
||||||
*/
|
*/
|
||||||
static fromEntropy(
|
static fromEntropy(
|
||||||
entropy: Uint8Array | number[],
|
entropy: Uint8Array | number[],
|
||||||
@@ -68,45 +77,50 @@ class Wallet {
|
|||||||
): Wallet {
|
): Wallet {
|
||||||
const options = {
|
const options = {
|
||||||
entropy: Uint8Array.from(entropy),
|
entropy: Uint8Array.from(entropy),
|
||||||
algorithm
|
algorithm,
|
||||||
}
|
};
|
||||||
const seed = generateSeed(options)
|
const seed = generateSeed(options);
|
||||||
return Wallet.deriveWallet(seed, algorithm)
|
return Wallet.deriveWallet(seed, algorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static hexFromBuffer(buffer: Buffer): string {
|
private static hexFromBuffer(buffer: Buffer): string {
|
||||||
return buffer.toString('hex').toUpperCase()
|
return buffer.toString("hex").toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static deriveWallet(seed: string, algorithm: ECDSA = Wallet.defaultAlgorithm): Wallet {
|
private static deriveWallet(
|
||||||
const {publicKey, privateKey} = deriveKeypair(seed, {algorithm})
|
seed: string,
|
||||||
return new Wallet(publicKey, privateKey)
|
algorithm: ECDSA = Wallet.defaultAlgorithm
|
||||||
|
): Wallet {
|
||||||
|
const { publicKey, privateKey } = deriveKeypair(seed, { algorithm });
|
||||||
|
return new Wallet(publicKey, privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs a transaction offline.
|
* Signs a transaction offline.
|
||||||
* @param {object} transaction A transaction to be signed offline.
|
*
|
||||||
* @param {SignOptions} options Options to include for signing.
|
* @param transaction - A transaction to be signed offline.
|
||||||
* @returns {SignedTransaction} A signed transaction.
|
* @param options - Options to include for signing.
|
||||||
|
* @returns A signed transaction.
|
||||||
*/
|
*/
|
||||||
signTransaction(
|
signTransaction(
|
||||||
transaction: any, // TODO: transaction should be typed with Transaction type.
|
transaction: any, // TODO: transaction should be typed with Transaction type.
|
||||||
options: SignOptions = {signAs: ''}
|
options: SignOptions = { signAs: "" }
|
||||||
): SignedTransaction {
|
): SignedTransaction {
|
||||||
return signOffline(this, JSON.stringify(transaction), options)
|
return signOffline(this, JSON.stringify(transaction), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies a signed transaction offline.
|
* Verifies a signed transaction offline.
|
||||||
* @param {string} signedTransaction A signed transaction (hex string of signTransaction result) to be verified offline.
|
*
|
||||||
* @returns {boolean} Returns true if a signedTransaction is valid.
|
* @param signedTransaction - A signed transaction (hex string of signTransaction result) to be verified offline.
|
||||||
|
* @returns Returns true if a signedTransaction is valid.
|
||||||
*/
|
*/
|
||||||
verifyTransaction(signedTransaction: string): boolean {
|
verifyTransaction(signedTransaction: string): boolean {
|
||||||
const tx = decode(signedTransaction)
|
const tx = decode(signedTransaction);
|
||||||
const messageHex: string = encodeForSigning(tx)
|
const messageHex: string = encodeForSigning(tx);
|
||||||
const signature = tx.TxnSignature
|
const signature = tx.TxnSignature;
|
||||||
return verify(messageHex, signature, this.publicKey)
|
return verify(messageHex, signature, this.publicKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Wallet
|
export default Wallet;
|
||||||
|
|||||||
@@ -1,44 +1,42 @@
|
|||||||
/*
|
// Original code based on "backo" - https://github.com/segmentio/backo
|
||||||
* Original code based on "backo" - https://github.com/segmentio/backo
|
// MIT License - Copyright 2014 Segment.io
|
||||||
* MIT License - Copyright 2014 Segment.io
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Back off strategy that increases exponentially. Useful with repeated
|
* A Back off strategy that increases exponentially. Useful with repeated
|
||||||
* setTimeout calls over a network (where the destination may be down).
|
* setTimeout calls over a network (where the destination may be down).
|
||||||
*/
|
*/
|
||||||
export class ExponentialBackoff {
|
export class ExponentialBackoff {
|
||||||
private readonly ms: number
|
private readonly ms: number;
|
||||||
private readonly max: number
|
private readonly max: number;
|
||||||
private readonly factor: number = 2
|
private readonly factor: number = 2;
|
||||||
private readonly jitter: number = 0
|
private readonly jitter: number = 0;
|
||||||
attempts: number = 0
|
attempts = 0;
|
||||||
|
|
||||||
constructor(opts: {min?: number; max?: number} = {}) {
|
constructor(opts: { min?: number; max?: number } = {}) {
|
||||||
this.ms = opts.min || 100
|
this.ms = opts.min || 100;
|
||||||
this.max = opts.max || 10000
|
this.max = opts.max || 10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the backoff duration.
|
* Return the backoff duration.
|
||||||
*/
|
*/
|
||||||
duration() {
|
duration() {
|
||||||
var ms = this.ms * Math.pow(this.factor, this.attempts++)
|
let ms = this.ms * this.factor ** this.attempts++;
|
||||||
if (this.jitter) {
|
if (this.jitter) {
|
||||||
var rand = Math.random()
|
const rand = Math.random();
|
||||||
var deviation = Math.floor(rand * this.jitter * ms)
|
const deviation = Math.floor(rand * this.jitter * ms);
|
||||||
ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation
|
ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation;
|
||||||
}
|
}
|
||||||
return Math.min(ms, this.max) | 0
|
return Math.min(ms, this.max) | 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the number of attempts.
|
* Reset the number of attempts.
|
||||||
*/
|
*/
|
||||||
reset() {
|
reset() {
|
||||||
this.attempts = 0
|
this.attempts = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +1,66 @@
|
|||||||
import {Client, ClientOptions} from './'
|
import { Client, ClientOptions } from ".";
|
||||||
|
|
||||||
class BroadcastClient extends Client {
|
class BroadcastClient extends Client {
|
||||||
ledgerVersion: number | undefined = undefined
|
ledgerVersion: number | undefined = undefined;
|
||||||
private _clients: Client[]
|
private readonly _clients: Client[];
|
||||||
|
|
||||||
constructor(servers, options: ClientOptions = {}) {
|
constructor(servers, options: ClientOptions = {}) {
|
||||||
super(servers[0], options)
|
super(servers[0], options);
|
||||||
|
|
||||||
const clients: Client[] = servers.map(
|
const clients: Client[] = servers.map(
|
||||||
(server) => new Client(server, options)
|
(server) => new Client(server, options)
|
||||||
)
|
);
|
||||||
|
|
||||||
// exposed for testing
|
// exposed for testing
|
||||||
this._clients = clients
|
this._clients = clients;
|
||||||
this.getMethodNames().forEach((name) => {
|
this.getMethodNames().forEach((name) => {
|
||||||
this[name] = function () {
|
this[name] = function () {
|
||||||
// eslint-disable-line no-loop-func
|
// eslint-disable-line no-loop-func
|
||||||
return Promise.race(clients.map((client) => client[name](...arguments)))
|
return Promise.race(
|
||||||
}
|
clients.map((client) => client[name](...arguments))
|
||||||
})
|
);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// connection methods must be overridden to apply to all client instances
|
// connection methods must be overridden to apply to all client instances
|
||||||
this.connect = async function () {
|
this.connect = async function () {
|
||||||
await Promise.all(clients.map((client) => client.connect()))
|
await Promise.all(clients.map((client) => client.connect()));
|
||||||
}
|
};
|
||||||
this.disconnect = async function () {
|
this.disconnect = async function () {
|
||||||
await Promise.all(clients.map((client) => client.disconnect()))
|
await Promise.all(clients.map((client) => client.disconnect()));
|
||||||
}
|
};
|
||||||
this.isConnected = function () {
|
this.isConnected = function () {
|
||||||
return clients.map((client) => client.isConnected()).every(Boolean)
|
return clients.map((client) => client.isConnected()).every(Boolean);
|
||||||
}
|
};
|
||||||
|
|
||||||
// synchronous methods are all passed directly to the first client instance
|
// synchronous methods are all passed directly to the first client instance
|
||||||
const defaultClient = clients[0]
|
const defaultClient = clients[0];
|
||||||
const syncMethods = ['sign']
|
const syncMethods = ["sign"];
|
||||||
syncMethods.forEach((name) => {
|
syncMethods.forEach((name) => {
|
||||||
this[name] = defaultClient[name].bind(defaultClient)
|
this[name] = defaultClient[name].bind(defaultClient);
|
||||||
})
|
});
|
||||||
|
|
||||||
clients.forEach((client) => {
|
clients.forEach((client) => {
|
||||||
client.on('error', (errorCode, errorMessage, data) =>
|
client.on("error", (errorCode, errorMessage, data) =>
|
||||||
this.emit('error', errorCode, errorMessage, data)
|
this.emit("error", errorCode, errorMessage, data)
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getMethodNames() {
|
getMethodNames() {
|
||||||
const methodNames: string[] = []
|
const methodNames: string[] = [];
|
||||||
const firstClient = this._clients[0]
|
const firstClient = this._clients[0];
|
||||||
const methods = Object.getOwnPropertyNames(firstClient)
|
const methods = Object.getOwnPropertyNames(firstClient);
|
||||||
methods.push(...Object.getOwnPropertyNames(Object.getPrototypeOf(firstClient)))
|
methods.push(
|
||||||
|
...Object.getOwnPropertyNames(Object.getPrototypeOf(firstClient))
|
||||||
|
);
|
||||||
for (const name of methods) {
|
for (const name of methods) {
|
||||||
if (typeof firstClient[name] === 'function' && name !== 'constructor') {
|
if (typeof firstClient[name] === "function" && name !== "constructor") {
|
||||||
methodNames.push(name)
|
methodNames.push(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return methodNames
|
return methodNames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {BroadcastClient}
|
export { BroadcastClient };
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import _ from 'lodash'
|
import { EventEmitter } from "events";
|
||||||
import {EventEmitter} from 'events'
|
import { parse as parseURL } from "url";
|
||||||
import {parse as parseURL} from 'url'
|
|
||||||
import WebSocket from 'ws'
|
import _ from "lodash";
|
||||||
|
import WebSocket from "ws";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
RippledError,
|
RippledError,
|
||||||
DisconnectedError,
|
DisconnectedError,
|
||||||
@@ -9,25 +11,26 @@ import {
|
|||||||
TimeoutError,
|
TimeoutError,
|
||||||
ResponseFormatError,
|
ResponseFormatError,
|
||||||
ConnectionError,
|
ConnectionError,
|
||||||
RippleError
|
RippleError,
|
||||||
} from '../common/errors'
|
} from "../common/errors";
|
||||||
import {ExponentialBackoff} from './backoff'
|
import { Response } from "../models/methods";
|
||||||
import { Response } from '../models/methods'
|
|
||||||
|
import { ExponentialBackoff } from "./backoff";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ConnectionOptions is the configuration for the Connection class.
|
* ConnectionOptions is the configuration for the Connection class.
|
||||||
*/
|
*/
|
||||||
export interface ConnectionOptions {
|
export interface ConnectionOptions {
|
||||||
trace?: boolean | ((id: string, message: string) => void)
|
trace?: boolean | ((id: string, message: string) => void);
|
||||||
proxy?: string
|
proxy?: string;
|
||||||
proxyAuthorization?: string
|
proxyAuthorization?: string;
|
||||||
authorization?: string
|
authorization?: string;
|
||||||
trustedCertificates?: string[]
|
trustedCertificates?: string[];
|
||||||
key?: string
|
key?: string;
|
||||||
passphrase?: string
|
passphrase?: string;
|
||||||
certificate?: string
|
certificate?: string;
|
||||||
timeout: number // request timeout
|
timeout: number; // request timeout
|
||||||
connectionTimeout: number
|
connectionTimeout: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,82 +38,88 @@ export interface ConnectionOptions {
|
|||||||
* is optional, so any ConnectionOptions configuration that has a default value is
|
* is optional, so any ConnectionOptions configuration that has a default value is
|
||||||
* still optional at the point that the user provides it.
|
* still optional at the point that the user provides it.
|
||||||
*/
|
*/
|
||||||
export type ConnectionUserOptions = Partial<ConnectionOptions>
|
export type ConnectionUserOptions = Partial<ConnectionOptions>;
|
||||||
|
|
||||||
/**
|
//
|
||||||
* Represents an intentionally triggered web-socket disconnect code.
|
// Represents an intentionally triggered web-socket disconnect code.
|
||||||
* WebSocket spec allows 4xxx codes for app/library specific codes.
|
// WebSocket spec allows 4xxx codes for app/library specific codes.
|
||||||
* See: https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
|
// See: https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
|
||||||
**/
|
//
|
||||||
const INTENTIONAL_DISCONNECT_CODE = 4000
|
const INTENTIONAL_DISCONNECT_CODE = 4000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new websocket given your URL and optional proxy/certificate
|
* Create a new websocket given your URL and optional proxy/certificate
|
||||||
* configuration.
|
* configuration.
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @param config
|
||||||
*/
|
*/
|
||||||
function createWebSocket(url: string, config: ConnectionOptions): WebSocket {
|
function createWebSocket(url: string, config: ConnectionOptions): WebSocket {
|
||||||
const options: WebSocket.ClientOptions = {}
|
const options: WebSocket.ClientOptions = {};
|
||||||
if (config.proxy != null) {
|
if (config.proxy != null) {
|
||||||
// TODO: replace deprecated method
|
// TODO: replace deprecated method
|
||||||
const parsedURL = parseURL(url)
|
const parsedURL = parseURL(url);
|
||||||
const parsedProxyURL = parseURL(config.proxy)
|
const parsedProxyURL = parseURL(config.proxy);
|
||||||
const proxyOverrides = _.omitBy(
|
const proxyOverrides = _.omitBy(
|
||||||
{
|
{
|
||||||
secureEndpoint: parsedURL.protocol === 'wss:',
|
secureEndpoint: parsedURL.protocol === "wss:",
|
||||||
secureProxy: parsedProxyURL.protocol === 'https:',
|
secureProxy: parsedProxyURL.protocol === "https:",
|
||||||
auth: config.proxyAuthorization,
|
auth: config.proxyAuthorization,
|
||||||
ca: config.trustedCertificates,
|
ca: config.trustedCertificates,
|
||||||
key: config.key,
|
key: config.key,
|
||||||
passphrase: config.passphrase,
|
passphrase: config.passphrase,
|
||||||
cert: config.certificate
|
cert: config.certificate,
|
||||||
},
|
},
|
||||||
(value) => value == null
|
(value) => value == null
|
||||||
)
|
);
|
||||||
const proxyOptions = {...parsedProxyURL, ...proxyOverrides}
|
const proxyOptions = { ...parsedProxyURL, ...proxyOverrides };
|
||||||
let HttpsProxyAgent
|
let HttpsProxyAgent;
|
||||||
try {
|
try {
|
||||||
HttpsProxyAgent = require('https-proxy-agent')
|
HttpsProxyAgent = require("https-proxy-agent");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error('"proxy" option is not supported in the browser')
|
throw new Error('"proxy" option is not supported in the browser');
|
||||||
}
|
}
|
||||||
options.agent = new HttpsProxyAgent(proxyOptions)
|
options.agent = new HttpsProxyAgent(proxyOptions);
|
||||||
}
|
}
|
||||||
if (config.authorization != null) {
|
if (config.authorization != null) {
|
||||||
const base64 = Buffer.from(config.authorization).toString('base64')
|
const base64 = Buffer.from(config.authorization).toString("base64");
|
||||||
options.headers = {Authorization: `Basic ${base64}`}
|
options.headers = { Authorization: `Basic ${base64}` };
|
||||||
}
|
}
|
||||||
const optionsOverrides = _.omitBy(
|
const optionsOverrides = _.omitBy(
|
||||||
{
|
{
|
||||||
ca: config.trustedCertificates,
|
ca: config.trustedCertificates,
|
||||||
key: config.key,
|
key: config.key,
|
||||||
passphrase: config.passphrase,
|
passphrase: config.passphrase,
|
||||||
cert: config.certificate
|
cert: config.certificate,
|
||||||
},
|
},
|
||||||
(value) => value == null
|
(value) => value == null
|
||||||
)
|
);
|
||||||
const websocketOptions = {...options, ...optionsOverrides}
|
const websocketOptions = { ...options, ...optionsOverrides };
|
||||||
const websocket = new WebSocket(url, null, websocketOptions)
|
const websocket = new WebSocket(url, websocketOptions);
|
||||||
// we will have a listener for each outstanding request,
|
// we will have a listener for each outstanding request,
|
||||||
// so we have to raise the limit (the default is 10)
|
// so we have to raise the limit (the default is 10)
|
||||||
if (typeof websocket.setMaxListeners === 'function') {
|
if (typeof websocket.setMaxListeners === "function") {
|
||||||
websocket.setMaxListeners(Infinity)
|
websocket.setMaxListeners(Infinity);
|
||||||
}
|
}
|
||||||
return websocket
|
return websocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ws.send(), but promisified.
|
* Ws.send(), but promisified.
|
||||||
|
*
|
||||||
|
* @param ws
|
||||||
|
* @param message
|
||||||
*/
|
*/
|
||||||
function websocketSendAsync(ws: WebSocket, message: string) {
|
function websocketSendAsync(ws: WebSocket, message: string) {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
ws.send(message, undefined, (error) => {
|
ws.send(message, (error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(new DisconnectedError(error.message, error))
|
reject(new DisconnectedError(error.message, error));
|
||||||
} else {
|
} else {
|
||||||
resolve()
|
resolve();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,25 +128,25 @@ function websocketSendAsync(ws: WebSocket, message: string) {
|
|||||||
* after-the-fact.
|
* after-the-fact.
|
||||||
*/
|
*/
|
||||||
class ConnectionManager {
|
class ConnectionManager {
|
||||||
private promisesAwaitingConnection: {
|
private promisesAwaitingConnection: Array<{
|
||||||
resolve: Function
|
resolve: Function;
|
||||||
reject: Function
|
reject: Function;
|
||||||
}[] = []
|
}> = [];
|
||||||
|
|
||||||
resolveAllAwaiting() {
|
resolveAllAwaiting() {
|
||||||
this.promisesAwaitingConnection.map(({resolve}) => resolve())
|
this.promisesAwaitingConnection.map(({ resolve }) => resolve());
|
||||||
this.promisesAwaitingConnection = []
|
this.promisesAwaitingConnection = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
rejectAllAwaiting(error: Error) {
|
rejectAllAwaiting(error: Error) {
|
||||||
this.promisesAwaitingConnection.map(({reject}) => reject(error))
|
this.promisesAwaitingConnection.map(({ reject }) => reject(error));
|
||||||
this.promisesAwaitingConnection = []
|
this.promisesAwaitingConnection = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
awaitConnection(): Promise<void> {
|
awaitConnection(): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.promisesAwaitingConnection.push({resolve, reject})
|
this.promisesAwaitingConnection.push({ resolve, reject });
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,231 +157,247 @@ class ConnectionManager {
|
|||||||
* original request.
|
* original request.
|
||||||
*/
|
*/
|
||||||
class RequestManager {
|
class RequestManager {
|
||||||
private nextId = 0
|
private nextId = 0;
|
||||||
private promisesAwaitingResponse: {
|
private promisesAwaitingResponse: Array<{
|
||||||
resolve: Function
|
resolve: Function;
|
||||||
reject: Function
|
reject: Function;
|
||||||
timer: NodeJS.Timeout
|
timer: NodeJS.Timeout;
|
||||||
}[] = []
|
}> = [];
|
||||||
|
|
||||||
cancel(id: number) {
|
cancel(id: number) {
|
||||||
const {timer} = this.promisesAwaitingResponse[id]
|
const { timer } = this.promisesAwaitingResponse[id];
|
||||||
clearTimeout(timer)
|
clearTimeout(timer);
|
||||||
delete this.promisesAwaitingResponse[id]
|
delete this.promisesAwaitingResponse[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(id: string | number, data: Response) {
|
resolve(id: string | number, data: Response) {
|
||||||
const {timer, resolve} = this.promisesAwaitingResponse[id]
|
const { timer, resolve } = this.promisesAwaitingResponse[id];
|
||||||
clearTimeout(timer)
|
clearTimeout(timer);
|
||||||
resolve(data)
|
resolve(data);
|
||||||
delete this.promisesAwaitingResponse[id]
|
delete this.promisesAwaitingResponse[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
reject(id: string | number, error: Error) {
|
reject(id: string | number, error: Error) {
|
||||||
const {timer, reject} = this.promisesAwaitingResponse[id]
|
const { timer, reject } = this.promisesAwaitingResponse[id];
|
||||||
clearTimeout(timer)
|
clearTimeout(timer);
|
||||||
reject(error)
|
reject(error);
|
||||||
delete this.promisesAwaitingResponse[id]
|
delete this.promisesAwaitingResponse[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
rejectAll(error: Error) {
|
rejectAll(error: Error) {
|
||||||
this.promisesAwaitingResponse.forEach((_, id) => {
|
this.promisesAwaitingResponse.forEach((_, id) => {
|
||||||
this.reject(id, error)
|
this.reject(id, error);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new WebSocket request. This sets up a timeout timer to catch
|
* Creates a new WebSocket request. This sets up a timeout timer to catch
|
||||||
* hung responses, and a promise that will resolve with the response once
|
* hung responses, and a promise that will resolve with the response once
|
||||||
* the response is seen & handled.
|
* the response is seen & handled.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param timeout
|
||||||
*/
|
*/
|
||||||
createRequest(data: any, timeout: number): [string | number, string, Promise<any>] {
|
createRequest(
|
||||||
const newId = data.id ? data.id : this.nextId++
|
data: any,
|
||||||
const newData = JSON.stringify({...data, id: newId})
|
timeout: number
|
||||||
|
): [string | number, string, Promise<any>] {
|
||||||
|
const newId = data.id ? data.id : this.nextId++;
|
||||||
|
const newData = JSON.stringify({ ...data, id: newId });
|
||||||
const timer = setTimeout(
|
const timer = setTimeout(
|
||||||
() => this.reject(newId, new TimeoutError()),
|
() => this.reject(newId, new TimeoutError()),
|
||||||
timeout
|
timeout
|
||||||
)
|
);
|
||||||
// Node.js won't exit if a timer is still running, so we tell Node to ignore.
|
// Node.js won't exit if a timer is still running, so we tell Node to ignore.
|
||||||
// (Node will still wait for the request to complete).
|
// (Node will still wait for the request to complete).
|
||||||
if (timer.unref) {
|
if (timer.unref) {
|
||||||
timer.unref()
|
timer.unref();
|
||||||
}
|
}
|
||||||
const newPromise = new Promise((resolve: (data: Response) => void, reject) => {
|
const newPromise = new Promise(
|
||||||
this.promisesAwaitingResponse[newId] = {resolve, reject, timer}
|
(resolve: (data: Response) => void, reject) => {
|
||||||
})
|
this.promisesAwaitingResponse[newId] = { resolve, reject, timer };
|
||||||
return [newId, newData, newPromise]
|
}
|
||||||
|
);
|
||||||
|
return [newId, newData, newPromise];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a "response". Responses match to the earlier request handlers,
|
* Handle a "response". Responses match to the earlier request handlers,
|
||||||
* and resolve/reject based on the data received.
|
* and resolve/reject based on the data received.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
*/
|
*/
|
||||||
handleResponse(data: Response) {
|
handleResponse(data: Response) {
|
||||||
if (!Number.isInteger(data.id) || data.id < 0) {
|
if (!Number.isInteger(data.id) || data.id < 0) {
|
||||||
throw new ResponseFormatError('valid id not found in response', data)
|
throw new ResponseFormatError("valid id not found in response", data);
|
||||||
}
|
}
|
||||||
if (!this.promisesAwaitingResponse[data.id]) {
|
if (!this.promisesAwaitingResponse[data.id]) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (data.status === 'error') {
|
if (data.status === "error") {
|
||||||
const error = new RippledError(data.error_message || data.error, data)
|
const error = new RippledError(data.error_message || data.error, data);
|
||||||
this.reject(data.id, error)
|
this.reject(data.id, error);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (data.status !== 'success') {
|
if (data.status !== "success") {
|
||||||
const error = new ResponseFormatError(
|
const error = new ResponseFormatError(
|
||||||
`unrecognized status: ${data.status}`,
|
`unrecognized status: ${data.status}`,
|
||||||
data
|
data
|
||||||
)
|
);
|
||||||
this.reject(data.id, error)
|
this.reject(data.id, error);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
this.resolve(data.id, data)
|
this.resolve(data.id, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main Connection class. Responsible for connecting to & managing
|
* The main Connection class. Responsible for connecting to & managing
|
||||||
* an active WebSocket connection to a XRPL node.
|
* an active WebSocket connection to a XRPL node.
|
||||||
|
*
|
||||||
|
* @param errorOrCode
|
||||||
*/
|
*/
|
||||||
export class Connection extends EventEmitter {
|
export class Connection extends EventEmitter {
|
||||||
private _url: string
|
private readonly _url: string | undefined;
|
||||||
private _ws: null | WebSocket = null
|
private _ws: null | WebSocket = null;
|
||||||
private _reconnectTimeoutID: null | NodeJS.Timeout = null
|
private _reconnectTimeoutID: null | NodeJS.Timeout = null;
|
||||||
private _heartbeatIntervalID: null | NodeJS.Timeout = null
|
private _heartbeatIntervalID: null | NodeJS.Timeout = null;
|
||||||
private _retryConnectionBackoff = new ExponentialBackoff({
|
private readonly _retryConnectionBackoff = new ExponentialBackoff({
|
||||||
min: 100,
|
min: 100,
|
||||||
max: 60 * 1000
|
max: 60 * 1000,
|
||||||
})
|
});
|
||||||
|
|
||||||
private _trace: (id: string, message: string) => void = () => {}
|
private readonly _trace: (id: string, message: string) => void = () => {};
|
||||||
private _config: ConnectionOptions
|
private readonly _config: ConnectionOptions;
|
||||||
private _requestManager = new RequestManager()
|
private readonly _requestManager = new RequestManager();
|
||||||
private _connectionManager = new ConnectionManager()
|
private readonly _connectionManager = new ConnectionManager();
|
||||||
|
|
||||||
constructor(url?: string, options: ConnectionUserOptions = {}) {
|
constructor(url?: string, options: ConnectionUserOptions = {}) {
|
||||||
super()
|
super();
|
||||||
this.setMaxListeners(Infinity)
|
this.setMaxListeners(Infinity);
|
||||||
this._url = url
|
this._url = url;
|
||||||
this._config = {
|
this._config = {
|
||||||
timeout: 20 * 1000,
|
timeout: 20 * 1000,
|
||||||
connectionTimeout: 5 * 1000,
|
connectionTimeout: 5 * 1000,
|
||||||
...options
|
...options,
|
||||||
}
|
};
|
||||||
if (typeof options.trace === 'function') {
|
if (typeof options.trace === "function") {
|
||||||
this._trace = options.trace
|
this._trace = options.trace;
|
||||||
} else if (options.trace === true) {
|
} else if (options.trace) {
|
||||||
this._trace = console.log
|
this._trace = console.log;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onMessage(message) {
|
private _onMessage(message) {
|
||||||
this._trace('receive', message)
|
this._trace("receive", message);
|
||||||
let data: any
|
let data: any;
|
||||||
try {
|
try {
|
||||||
data = JSON.parse(message)
|
data = JSON.parse(message);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.emit('error', 'badMessage', error.message, message)
|
this.emit("error", "badMessage", error.message, message);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (data.type == null && data.error) {
|
if (data.type == null && data.error) {
|
||||||
this.emit('error', data.error, data.error_message, data) // e.g. slowDown
|
this.emit("error", data.error, data.error_message, data); // e.g. slowDown
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (data.type) {
|
if (data.type) {
|
||||||
this.emit(data.type, data)
|
this.emit(data.type, data);
|
||||||
}
|
}
|
||||||
if (data.type === 'response') {
|
if (data.type === "response") {
|
||||||
try {
|
try {
|
||||||
this._requestManager.handleResponse(data)
|
this._requestManager.handleResponse(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.emit('error', 'badMessage', error.message, message)
|
this.emit("error", "badMessage", error.message, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _state() {
|
private get _state() {
|
||||||
return this._ws ? this._ws.readyState : WebSocket.CLOSED
|
return this._ws ? this._ws.readyState : WebSocket.CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _shouldBeConnected() {
|
private get _shouldBeConnected() {
|
||||||
return this._ws !== null
|
return this._ws !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _clearHeartbeatInterval = () => {
|
private readonly _clearHeartbeatInterval = () => {
|
||||||
clearInterval(this._heartbeatIntervalID)
|
if (this._heartbeatIntervalID) {
|
||||||
}
|
clearInterval(this._heartbeatIntervalID);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private _startHeartbeatInterval = () => {
|
private readonly _startHeartbeatInterval = () => {
|
||||||
this._clearHeartbeatInterval()
|
this._clearHeartbeatInterval();
|
||||||
this._heartbeatIntervalID = setInterval(
|
this._heartbeatIntervalID = setInterval(
|
||||||
() => this._heartbeat(),
|
() => this._heartbeat(),
|
||||||
this._config.timeout
|
this._config.timeout
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A heartbeat is just a "ping" command, sent on an interval.
|
* A heartbeat is just a "ping" command, sent on an interval.
|
||||||
* If this succeeds, we're good. If it fails, disconnect so that the consumer can reconnect, if desired.
|
* If this succeeds, we're good. If it fails, disconnect so that the consumer can reconnect, if desired.
|
||||||
*/
|
*/
|
||||||
private _heartbeat = () => {
|
private readonly _heartbeat = () => {
|
||||||
return this.request({command: 'ping'}).catch(() => {
|
return this.request({ command: "ping" }).catch(() => {
|
||||||
return this.reconnect().catch((error) => {
|
return this.reconnect().catch((error) => {
|
||||||
this.emit('error', 'reconnect', error.message, error)
|
this.emit("error", "reconnect", error.message, error);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
private _onConnectionFailed = (errorOrCode: Error | number | null) => {
|
private readonly _onConnectionFailed = (
|
||||||
|
errorOrCode: Error | number | null
|
||||||
|
) => {
|
||||||
if (this._ws) {
|
if (this._ws) {
|
||||||
this._ws.removeAllListeners()
|
this._ws.removeAllListeners();
|
||||||
this._ws.on('error', () => {
|
this._ws.on("error", () => {
|
||||||
// Correctly listen for -- but ignore -- any future errors: If you
|
// Correctly listen for -- but ignore -- any future errors: If you
|
||||||
// don't have a listener on "error" node would log a warning on error.
|
// don't have a listener on "error" node would log a warning on error.
|
||||||
})
|
});
|
||||||
this._ws.close()
|
this._ws.close();
|
||||||
this._ws = null
|
this._ws = null;
|
||||||
}
|
}
|
||||||
if (typeof errorOrCode === 'number') {
|
if (typeof errorOrCode === "number") {
|
||||||
this._connectionManager.rejectAllAwaiting(
|
this._connectionManager.rejectAllAwaiting(
|
||||||
new NotConnectedError(`Connection failed with code ${errorOrCode}.`, {
|
new NotConnectedError(`Connection failed with code ${errorOrCode}.`, {
|
||||||
code: errorOrCode
|
code: errorOrCode,
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
} else if (errorOrCode && errorOrCode.message) {
|
} else if (errorOrCode && errorOrCode.message) {
|
||||||
this._connectionManager.rejectAllAwaiting(
|
this._connectionManager.rejectAllAwaiting(
|
||||||
new NotConnectedError(errorOrCode.message, errorOrCode)
|
new NotConnectedError(errorOrCode.message, errorOrCode)
|
||||||
)
|
);
|
||||||
} else {
|
} else {
|
||||||
this._connectionManager.rejectAllAwaiting(
|
this._connectionManager.rejectAllAwaiting(
|
||||||
new NotConnectedError('Connection failed.')
|
new NotConnectedError("Connection failed.")
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
isConnected() {
|
isConnected() {
|
||||||
return this._state === WebSocket.OPEN
|
return this._state === WebSocket.OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(): Promise<void> {
|
connect(): Promise<void> {
|
||||||
if (this.isConnected()) {
|
if (this.isConnected()) {
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
if (this._state === WebSocket.CONNECTING) {
|
if (this._state === WebSocket.CONNECTING) {
|
||||||
return this._connectionManager.awaitConnection()
|
return this._connectionManager.awaitConnection();
|
||||||
}
|
}
|
||||||
if (!this._url) {
|
if (!this._url) {
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
new ConnectionError('Cannot connect because no server was specified')
|
new ConnectionError("Cannot connect because no server was specified")
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
if (this._ws) {
|
if (this._ws) {
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
new RippleError('Websocket connection never cleaned up.', {
|
new RippleError("Websocket connection never cleaned up.", {
|
||||||
state: this._state
|
state: this._state,
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the connection timeout, in case the connection hangs longer than expected.
|
// Create the connection timeout, in case the connection hangs longer than expected.
|
||||||
@@ -383,58 +408,71 @@ export class Connection extends EventEmitter {
|
|||||||
`If your internet connection is working, the rippled server may be blocked or inaccessible. ` +
|
`If your internet connection is working, the rippled server may be blocked or inaccessible. ` +
|
||||||
`You can also try setting the 'connectionTimeout' option in the Client constructor.`
|
`You can also try setting the 'connectionTimeout' option in the Client constructor.`
|
||||||
)
|
)
|
||||||
)
|
);
|
||||||
}, this._config.connectionTimeout)
|
}, this._config.connectionTimeout);
|
||||||
// Connection listeners: these stay attached only until a connection is done/open.
|
// Connection listeners: these stay attached only until a connection is done/open.
|
||||||
this._ws = createWebSocket(this._url, this._config)
|
this._ws = createWebSocket(this._url, this._config);
|
||||||
this._ws.on('error', this._onConnectionFailed)
|
|
||||||
this._ws.on('error', () => clearTimeout(connectionTimeoutID))
|
if (this._ws == null) {
|
||||||
this._ws.on('close', this._onConnectionFailed)
|
throw new Error("Connect: created null websocket");
|
||||||
this._ws.on('close', () => clearTimeout(connectionTimeoutID))
|
}
|
||||||
this._ws.once('open', async () => {
|
|
||||||
|
this._ws.on("error", this._onConnectionFailed);
|
||||||
|
this._ws.on("error", () => clearTimeout(connectionTimeoutID));
|
||||||
|
this._ws.on("close", this._onConnectionFailed);
|
||||||
|
this._ws.on("close", () => clearTimeout(connectionTimeoutID));
|
||||||
|
this._ws.once("open", async () => {
|
||||||
|
if (this._ws == null) {
|
||||||
|
throw new Error("onceOpen: ws is null");
|
||||||
|
}
|
||||||
|
|
||||||
// Once the connection completes successfully, remove all old listeners
|
// Once the connection completes successfully, remove all old listeners
|
||||||
this._ws.removeAllListeners()
|
this._ws.removeAllListeners();
|
||||||
clearTimeout(connectionTimeoutID)
|
clearTimeout(connectionTimeoutID);
|
||||||
// Add new, long-term connected listeners for messages and errors
|
// Add new, long-term connected listeners for messages and errors
|
||||||
this._ws.on('message', (message: string) => this._onMessage(message))
|
this._ws.on("message", (message: string) => this._onMessage(message));
|
||||||
this._ws.on('error', (error) =>
|
this._ws.on("error", (error) =>
|
||||||
this.emit('error', 'websocket', error.message, error)
|
this.emit("error", "websocket", error.message, error)
|
||||||
)
|
);
|
||||||
// Handle a closed connection: reconnect if it was unexpected
|
// Handle a closed connection: reconnect if it was unexpected
|
||||||
this._ws.once('close', (code, reason) => {
|
this._ws.once("close", (code, reason) => {
|
||||||
this._clearHeartbeatInterval()
|
if (this._ws == null) {
|
||||||
|
throw new Error("onceClose: ws is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._clearHeartbeatInterval();
|
||||||
this._requestManager.rejectAll(
|
this._requestManager.rejectAll(
|
||||||
new DisconnectedError(`websocket was closed, ${reason}`)
|
new DisconnectedError(`websocket was closed, ${reason}`)
|
||||||
)
|
);
|
||||||
this._ws.removeAllListeners()
|
this._ws.removeAllListeners();
|
||||||
this._ws = null
|
this._ws = null;
|
||||||
this.emit('disconnected', code)
|
this.emit("disconnected", code);
|
||||||
// If this wasn't a manual disconnect, then lets reconnect ASAP.
|
// If this wasn't a manual disconnect, then lets reconnect ASAP.
|
||||||
if (code !== INTENTIONAL_DISCONNECT_CODE) {
|
if (code !== INTENTIONAL_DISCONNECT_CODE) {
|
||||||
const retryTimeout = this._retryConnectionBackoff.duration()
|
const retryTimeout = this._retryConnectionBackoff.duration();
|
||||||
this._trace('reconnect', `Retrying connection in ${retryTimeout}ms.`)
|
this._trace("reconnect", `Retrying connection in ${retryTimeout}ms.`);
|
||||||
this.emit('reconnecting', this._retryConnectionBackoff.attempts)
|
this.emit("reconnecting", this._retryConnectionBackoff.attempts);
|
||||||
// Start the reconnect timeout, but set it to `this._reconnectTimeoutID`
|
// Start the reconnect timeout, but set it to `this._reconnectTimeoutID`
|
||||||
// so that we can cancel one in-progress on disconnect.
|
// so that we can cancel one in-progress on disconnect.
|
||||||
this._reconnectTimeoutID = setTimeout(() => {
|
this._reconnectTimeoutID = setTimeout(() => {
|
||||||
this.reconnect().catch((error) => {
|
this.reconnect().catch((error) => {
|
||||||
this.emit('error', 'reconnect', error.message, error)
|
this.emit("error", "reconnect", error.message, error);
|
||||||
})
|
});
|
||||||
}, retryTimeout)
|
}, retryTimeout);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
// Finalize the connection and resolve all awaiting connect() requests
|
// Finalize the connection and resolve all awaiting connect() requests
|
||||||
try {
|
try {
|
||||||
this._retryConnectionBackoff.reset()
|
this._retryConnectionBackoff.reset();
|
||||||
this._startHeartbeatInterval()
|
this._startHeartbeatInterval();
|
||||||
this._connectionManager.resolveAllAwaiting()
|
this._connectionManager.resolveAllAwaiting();
|
||||||
this.emit('connected')
|
this.emit("connected");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this._connectionManager.rejectAllAwaiting(error)
|
this._connectionManager.rejectAllAwaiting(error);
|
||||||
await this.disconnect().catch(() => {}) // Ignore this error, propagate the root cause.
|
await this.disconnect().catch(() => {}); // Ignore this error, propagate the root cause.
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return this._connectionManager.awaitConnection()
|
return this._connectionManager.awaitConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -445,20 +483,30 @@ export class Connection extends EventEmitter {
|
|||||||
* If no open websocket connection exists, resolve with no code (`undefined`).
|
* If no open websocket connection exists, resolve with no code (`undefined`).
|
||||||
*/
|
*/
|
||||||
disconnect(): Promise<number | undefined> {
|
disconnect(): Promise<number | undefined> {
|
||||||
clearTimeout(this._reconnectTimeoutID)
|
if (this._reconnectTimeoutID !== null) {
|
||||||
this._reconnectTimeoutID = null
|
clearTimeout(this._reconnectTimeoutID);
|
||||||
if (this._state === WebSocket.CLOSED || !this._ws) {
|
this._reconnectTimeoutID = null;
|
||||||
return Promise.resolve(undefined)
|
|
||||||
}
|
}
|
||||||
|
if (this._state === WebSocket.CLOSED) {
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
|
if (this._ws === null) {
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this._ws.once('close', (code) => resolve(code))
|
if (this._ws === null) {
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._ws.once("close", (code) => resolve(code));
|
||||||
// Connection already has a disconnect handler for the disconnect logic.
|
// Connection already has a disconnect handler for the disconnect logic.
|
||||||
// Just close the websocket manually (with our "intentional" code) to
|
// Just close the websocket manually (with our "intentional" code) to
|
||||||
// trigger that.
|
// trigger that.
|
||||||
if (this._state !== WebSocket.CLOSING) {
|
if (this._ws != null && this._state !== WebSocket.CLOSING) {
|
||||||
this._ws.close(INTENTIONAL_DISCONNECT_CODE)
|
this._ws.close(INTENTIONAL_DISCONNECT_CODE);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -468,33 +516,36 @@ export class Connection extends EventEmitter {
|
|||||||
// NOTE: We currently have a "reconnecting" event, but that only triggers
|
// NOTE: We currently have a "reconnecting" event, but that only triggers
|
||||||
// through an unexpected connection retry logic.
|
// through an unexpected connection retry logic.
|
||||||
// See: https://github.com/ripple/ripple-lib/pull/1101#issuecomment-565360423
|
// See: https://github.com/ripple/ripple-lib/pull/1101#issuecomment-565360423
|
||||||
this.emit('reconnect')
|
this.emit("reconnect");
|
||||||
await this.disconnect()
|
await this.disconnect();
|
||||||
await this.connect()
|
await this.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
async request<T extends {command: string}>(request: T, timeout?: number): Promise<any> {
|
async request<T extends { command: string }>(
|
||||||
if (!this._shouldBeConnected) {
|
request: T,
|
||||||
throw new NotConnectedError()
|
timeout?: number
|
||||||
|
): Promise<any> {
|
||||||
|
if (!this._shouldBeConnected || this._ws == null) {
|
||||||
|
throw new NotConnectedError();
|
||||||
}
|
}
|
||||||
const [id, message, responsePromise] = this._requestManager.createRequest(
|
const [id, message, responsePromise] = this._requestManager.createRequest(
|
||||||
request,
|
request,
|
||||||
timeout || this._config.timeout
|
timeout || this._config.timeout
|
||||||
)
|
);
|
||||||
this._trace('send', message)
|
this._trace("send", message);
|
||||||
websocketSendAsync(this._ws, message).catch((error) => {
|
websocketSendAsync(this._ws, message).catch((error) => {
|
||||||
this._requestManager.reject(id, error)
|
this._requestManager.reject(id, error);
|
||||||
})
|
});
|
||||||
|
|
||||||
return responsePromise
|
return responsePromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Websocket connection URL
|
* Get the Websocket connection URL.
|
||||||
*
|
*
|
||||||
* @returns The Websocket connection URL
|
* @returns The Websocket connection URL.
|
||||||
*/
|
*/
|
||||||
getUrl(): string {
|
getUrl(): string {
|
||||||
return this._url
|
return this._url ?? "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,31 @@
|
|||||||
import {EventEmitter} from 'events'
|
import { EventEmitter } from "events";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
constants,
|
classicAddressToXAddress,
|
||||||
errors,
|
xAddressToClassicAddress,
|
||||||
txFlags,
|
isValidXAddress,
|
||||||
} from '../common'
|
isValidClassicAddress,
|
||||||
import { Connection, ConnectionUserOptions } from './connection'
|
encodeSeed,
|
||||||
import getTrustlines from '../ledger/trustlines'
|
decodeSeed,
|
||||||
import getBalances from '../ledger/balances'
|
encodeAccountID,
|
||||||
import getPaths from '../ledger/pathfind'
|
decodeAccountID,
|
||||||
import {getOrderbook, formatBidsAndAsks} from '../ledger/orderbook'
|
encodeNodePublic,
|
||||||
import preparePayment from '../transaction/payment'
|
decodeNodePublic,
|
||||||
import prepareTrustline from '../transaction/trustline'
|
encodeAccountPublic,
|
||||||
import prepareOrder from '../transaction/order'
|
decodeAccountPublic,
|
||||||
import prepareOrderCancellation from '../transaction/ordercancellation'
|
encodeXAddress,
|
||||||
import prepareEscrowCreation from '../transaction/escrow-creation'
|
decodeXAddress,
|
||||||
import prepareEscrowExecution from '../transaction/escrow-execution'
|
} from "ripple-address-codec";
|
||||||
import prepareEscrowCancellation from '../transaction/escrow-cancellation'
|
|
||||||
import preparePaymentChannelCreate from '../transaction/payment-channel-create'
|
import { constants, errors, txFlags, ensureClassicAddress } from "../common";
|
||||||
import preparePaymentChannelFund from '../transaction/payment-channel-fund'
|
import { ValidationError } from "../common/errors";
|
||||||
import preparePaymentChannelClaim from '../transaction/payment-channel-claim'
|
import { getFee } from "../common/fee";
|
||||||
import prepareCheckCreate from '../transaction/check-create'
|
import * as schemaValidator from "../common/schema-validator";
|
||||||
import prepareCheckCancel from '../transaction/check-cancel'
|
import getBalances from "../ledger/balances";
|
||||||
import prepareCheckCash from '../transaction/check-cash'
|
import { getOrderbook, formatBidsAndAsks } from "../ledger/orderbook";
|
||||||
import prepareSettings from '../transaction/settings'
|
import getPaths from "../ledger/pathfind";
|
||||||
import prepareTicketCreate from '../transaction/ticket'
|
import getTrustlines from "../ledger/trustlines";
|
||||||
import {sign} from '../transaction/sign'
|
import { clamp } from "../ledger/utils";
|
||||||
import combine from '../transaction/combine'
|
|
||||||
import {deriveAddress, deriveXAddress} from '../utils/derive'
|
|
||||||
import {
|
import {
|
||||||
Request,
|
Request,
|
||||||
Response,
|
Response,
|
||||||
@@ -94,162 +93,172 @@ import {
|
|||||||
PingRequest,
|
PingRequest,
|
||||||
PingResponse,
|
PingResponse,
|
||||||
RandomRequest,
|
RandomRequest,
|
||||||
RandomResponse
|
RandomResponse,
|
||||||
} from '../models/methods'
|
} from "../models/methods";
|
||||||
|
import prepareCheckCancel from "../transaction/check-cancel";
|
||||||
|
import prepareCheckCash from "../transaction/check-cash";
|
||||||
|
import prepareCheckCreate from "../transaction/check-create";
|
||||||
|
import combine from "../transaction/combine";
|
||||||
|
import prepareEscrowCancellation from "../transaction/escrow-cancellation";
|
||||||
|
import prepareEscrowCreation from "../transaction/escrow-creation";
|
||||||
|
import prepareEscrowExecution from "../transaction/escrow-execution";
|
||||||
|
import prepareOrder from "../transaction/order";
|
||||||
|
import prepareOrderCancellation from "../transaction/ordercancellation";
|
||||||
|
import preparePayment from "../transaction/payment";
|
||||||
|
import preparePaymentChannelClaim from "../transaction/payment-channel-claim";
|
||||||
|
import preparePaymentChannelCreate from "../transaction/payment-channel-create";
|
||||||
|
import preparePaymentChannelFund from "../transaction/payment-channel-fund";
|
||||||
|
import prepareSettings from "../transaction/settings";
|
||||||
|
import { sign } from "../transaction/sign";
|
||||||
|
import prepareTicketCreate from "../transaction/ticket";
|
||||||
|
import prepareTrustline from "../transaction/trustline";
|
||||||
|
import { TransactionJSON, Instructions, Prepare } from "../transaction/types";
|
||||||
|
import * as transactionUtils from "../transaction/utils";
|
||||||
|
import { deriveAddress, deriveXAddress } from "../utils/derive";
|
||||||
|
import generateFaucetWallet from "../wallet/wallet-generation";
|
||||||
|
|
||||||
import * as transactionUtils from '../transaction/utils'
|
import { Connection, ConnectionUserOptions } from "./connection";
|
||||||
import * as schemaValidator from '../common/schema-validator'
|
|
||||||
import {getFee} from '../common/fee'
|
|
||||||
import {ensureClassicAddress} from '../common'
|
|
||||||
import {clamp} from '../ledger/utils'
|
|
||||||
import {TransactionJSON, Instructions, Prepare} from '../transaction/types'
|
|
||||||
import {
|
|
||||||
classicAddressToXAddress,
|
|
||||||
xAddressToClassicAddress,
|
|
||||||
isValidXAddress,
|
|
||||||
isValidClassicAddress,
|
|
||||||
encodeSeed,
|
|
||||||
decodeSeed,
|
|
||||||
encodeAccountID,
|
|
||||||
decodeAccountID,
|
|
||||||
encodeNodePublic,
|
|
||||||
decodeNodePublic,
|
|
||||||
encodeAccountPublic,
|
|
||||||
decodeAccountPublic,
|
|
||||||
encodeXAddress,
|
|
||||||
decodeXAddress
|
|
||||||
} from 'ripple-address-codec'
|
|
||||||
import generateFaucetWallet from '../wallet/wallet-generation'
|
|
||||||
import { ValidationError } from '../common/errors'
|
|
||||||
|
|
||||||
export interface ClientOptions extends ConnectionUserOptions {
|
export interface ClientOptions extends ConnectionUserOptions {
|
||||||
feeCushion?: number
|
feeCushion?: number;
|
||||||
maxFeeXRP?: string
|
maxFeeXRP?: string;
|
||||||
proxy?: string
|
proxy?: string;
|
||||||
timeout?: number
|
timeout?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the response key / property name that contains the listed data for a
|
* Get the response key / property name that contains the listed data for a
|
||||||
* command. This varies from command to command, but we need to know it to
|
* command. This varies from command to command, but we need to know it to
|
||||||
* properly count across many requests.
|
* properly count across many requests.
|
||||||
|
*
|
||||||
|
* @param command
|
||||||
*/
|
*/
|
||||||
function getCollectKeyFromCommand(command: string): string | null {
|
function getCollectKeyFromCommand(command: string): string | null {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'account_channels':
|
case "account_channels":
|
||||||
return 'channels'
|
return "channels";
|
||||||
case 'account_lines':
|
case "account_lines":
|
||||||
return 'lines'
|
return "lines";
|
||||||
case 'account_objects':
|
case "account_objects":
|
||||||
return 'account_objects'
|
return "account_objects";
|
||||||
case 'account_tx':
|
case "account_tx":
|
||||||
return 'transactions'
|
return "transactions";
|
||||||
case 'account_offers':
|
case "account_offers":
|
||||||
case 'book_offers':
|
case "book_offers":
|
||||||
return 'offers'
|
return "offers";
|
||||||
case 'ledger_data':
|
case "ledger_data":
|
||||||
return 'state'
|
return "state";
|
||||||
default:
|
default:
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MarkerRequest = AccountChannelsRequest
|
type MarkerRequest =
|
||||||
| AccountLinesRequest
|
| AccountChannelsRequest
|
||||||
| AccountObjectsRequest
|
| AccountLinesRequest
|
||||||
| AccountOffersRequest
|
| AccountObjectsRequest
|
||||||
| AccountTxRequest
|
| AccountOffersRequest
|
||||||
| LedgerDataRequest
|
| AccountTxRequest
|
||||||
|
| LedgerDataRequest;
|
||||||
|
|
||||||
type MarkerResponse = AccountChannelsResponse
|
type MarkerResponse =
|
||||||
| AccountLinesResponse
|
| AccountChannelsResponse
|
||||||
| AccountObjectsResponse
|
| AccountLinesResponse
|
||||||
| AccountOffersResponse
|
| AccountObjectsResponse
|
||||||
| AccountTxResponse
|
| AccountOffersResponse
|
||||||
| LedgerDataResponse
|
| AccountTxResponse
|
||||||
|
| LedgerDataResponse;
|
||||||
|
|
||||||
class Client extends EventEmitter {
|
class Client extends EventEmitter {
|
||||||
// Factor to multiply estimated fee by to provide a cushion in case the
|
// Factor to multiply estimated fee by to provide a cushion in case the
|
||||||
// required fee rises during submission of a transaction. Defaults to 1.2.
|
// required fee rises during submission of a transaction. Defaults to 1.2.
|
||||||
_feeCushion: number
|
_feeCushion: number;
|
||||||
// Maximum fee to use with transactions, in XRP. Must be a string-encoded
|
// Maximum fee to use with transactions, in XRP. Must be a string-encoded
|
||||||
// number. Defaults to '2'.
|
// number. Defaults to '2'.
|
||||||
_maxFeeXRP: string
|
_maxFeeXRP: string;
|
||||||
|
|
||||||
// New in > 0.21.0
|
// New in > 0.21.0
|
||||||
// non-validated ledger versions are allowed, and passed to rippled as-is.
|
// non-validated ledger versions are allowed, and passed to rippled as-is.
|
||||||
connection: Connection
|
connection: Connection;
|
||||||
|
|
||||||
constructor(server: string, options: ClientOptions = {}) {
|
constructor(server: string, options: ClientOptions = {}) {
|
||||||
super()
|
super();
|
||||||
if (typeof server !== 'string' || !server.match("^(wss?|wss?\\+unix)://")) {
|
if (typeof server !== "string" || !server.match("^(wss?|wss?\\+unix)://")) {
|
||||||
throw new ValidationError("server URI must start with `wss://`, `ws://`, `wss+unix://`, or `ws+unix://`.")
|
throw new ValidationError(
|
||||||
|
"server URI must start with `wss://`, `ws://`, `wss+unix://`, or `ws+unix://`."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._feeCushion = options.feeCushion || 1.2
|
this._feeCushion = options.feeCushion || 1.2;
|
||||||
this._maxFeeXRP = options.maxFeeXRP || '2'
|
this._maxFeeXRP = options.maxFeeXRP || "2";
|
||||||
|
|
||||||
this.connection = new Connection(server, options)
|
this.connection = new Connection(server, options);
|
||||||
|
|
||||||
this.connection.on('error', (errorCode, errorMessage, data) => {
|
this.connection.on("error", (errorCode, errorMessage, data) => {
|
||||||
this.emit('error', errorCode, errorMessage, data)
|
this.emit("error", errorCode, errorMessage, data);
|
||||||
})
|
});
|
||||||
|
|
||||||
this.connection.on('connected', () => {
|
this.connection.on("connected", () => {
|
||||||
this.emit('connected')
|
this.emit("connected");
|
||||||
})
|
});
|
||||||
|
|
||||||
this.connection.on('disconnected', (code) => {
|
this.connection.on("disconnected", (code) => {
|
||||||
let finalCode = code
|
let finalCode = code;
|
||||||
// 4000: Connection uses a 4000 code internally to indicate a manual disconnect/close
|
// 4000: Connection uses a 4000 code internally to indicate a manual disconnect/close
|
||||||
// Since 4000 is a normal disconnect reason, we convert this to the standard exit code 1000
|
// Since 4000 is a normal disconnect reason, we convert this to the standard exit code 1000
|
||||||
if (finalCode === 4000) {
|
if (finalCode === 4000) {
|
||||||
finalCode = 1000
|
finalCode = 1000;
|
||||||
}
|
}
|
||||||
this.emit('disconnected', finalCode)
|
this.emit("disconnected", finalCode);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a request to the client with the given command and
|
* Makes a request to the client with the given command and
|
||||||
* additional request body parameters.
|
* additional request body parameters.
|
||||||
*/
|
*/
|
||||||
public request(r: AccountChannelsRequest): Promise<AccountChannelsResponse>
|
public request(r: AccountChannelsRequest): Promise<AccountChannelsResponse>;
|
||||||
public request(r: AccountCurrenciesRequest): Promise<AccountCurrenciesResponse>
|
public request(
|
||||||
public request(r: AccountInfoRequest): Promise<AccountInfoResponse>
|
r: AccountCurrenciesRequest
|
||||||
public request(r: AccountLinesRequest): Promise<AccountLinesResponse>
|
): Promise<AccountCurrenciesResponse>;
|
||||||
public request(r: AccountObjectsRequest): Promise<AccountObjectsResponse>
|
public request(r: AccountInfoRequest): Promise<AccountInfoResponse>;
|
||||||
public request(r: AccountOffersRequest): Promise<AccountOffersResponse>
|
public request(r: AccountLinesRequest): Promise<AccountLinesResponse>;
|
||||||
public request(r: AccountTxRequest): Promise<AccountTxResponse>
|
public request(r: AccountObjectsRequest): Promise<AccountObjectsResponse>;
|
||||||
public request(r: BookOffersRequest): Promise<BookOffersResponse>
|
public request(r: AccountOffersRequest): Promise<AccountOffersResponse>;
|
||||||
public request(r: ChannelVerifyRequest): Promise<ChannelVerifyResponse>
|
public request(r: AccountTxRequest): Promise<AccountTxResponse>;
|
||||||
public request(r: DepositAuthorizedRequest): Promise<DepositAuthorizedResponse>
|
public request(r: BookOffersRequest): Promise<BookOffersResponse>;
|
||||||
public request(r: FeeRequest): Promise<FeeResponse>
|
public request(r: ChannelVerifyRequest): Promise<ChannelVerifyResponse>;
|
||||||
public request(r: GatewayBalancesRequest): Promise<GatewayBalancesResponse>
|
public request(
|
||||||
public request(r: LedgerRequest): Promise<LedgerResponse>
|
r: DepositAuthorizedRequest
|
||||||
public request(r: LedgerClosedRequest): Promise<LedgerClosedResponse>
|
): Promise<DepositAuthorizedResponse>;
|
||||||
public request(r: LedgerCurrentRequest): Promise<LedgerCurrentResponse>
|
public request(r: FeeRequest): Promise<FeeResponse>;
|
||||||
public request(r: LedgerDataRequest): Promise<LedgerDataResponse>
|
public request(r: GatewayBalancesRequest): Promise<GatewayBalancesResponse>;
|
||||||
public request(r: LedgerEntryRequest): Promise<LedgerEntryResponse>
|
public request(r: LedgerRequest): Promise<LedgerResponse>;
|
||||||
public request(r: ManifestRequest): Promise<ManifestResponse>
|
public request(r: LedgerClosedRequest): Promise<LedgerClosedResponse>;
|
||||||
public request(r: NoRippleCheckRequest): Promise<NoRippleCheckResponse>
|
public request(r: LedgerCurrentRequest): Promise<LedgerCurrentResponse>;
|
||||||
public request(r: PathFindRequest): Promise<PathFindResponse>
|
public request(r: LedgerDataRequest): Promise<LedgerDataResponse>;
|
||||||
public request(r: PingRequest): Promise<PingResponse>
|
public request(r: LedgerEntryRequest): Promise<LedgerEntryResponse>;
|
||||||
public request(r: RandomRequest): Promise<RandomResponse>
|
public request(r: ManifestRequest): Promise<ManifestResponse>;
|
||||||
public request(r: RipplePathFindRequest): Promise<RipplePathFindResponse>
|
public request(r: NoRippleCheckRequest): Promise<NoRippleCheckResponse>;
|
||||||
public request(r: ServerInfoRequest): Promise<ServerInfoResponse>
|
public request(r: PathFindRequest): Promise<PathFindResponse>;
|
||||||
public request(r: ServerStateRequest): Promise<ServerStateResponse>
|
public request(r: PingRequest): Promise<PingResponse>;
|
||||||
public request(r: SubmitRequest): Promise<SubmitResponse>
|
public request(r: RandomRequest): Promise<RandomResponse>;
|
||||||
public request(r: SubmitMultisignedRequest): Promise<SubmitMultisignedResponse>
|
public request(r: RipplePathFindRequest): Promise<RipplePathFindResponse>;
|
||||||
public request(r: TransactionEntryRequest): Promise<TransactionEntryResponse>
|
public request(r: ServerInfoRequest): Promise<ServerInfoResponse>;
|
||||||
public request(r: TxRequest): Promise<TxResponse>
|
public request(r: ServerStateRequest): Promise<ServerStateResponse>;
|
||||||
|
public request(r: SubmitRequest): Promise<SubmitResponse>;
|
||||||
|
public request(
|
||||||
|
r: SubmitMultisignedRequest
|
||||||
|
): Promise<SubmitMultisignedResponse>;
|
||||||
|
public request(r: TransactionEntryRequest): Promise<TransactionEntryResponse>;
|
||||||
|
public request(r: TxRequest): Promise<TxResponse>;
|
||||||
public request<R extends Request, T extends Response>(r: R): Promise<T> {
|
public request<R extends Request, T extends Response>(r: R): Promise<T> {
|
||||||
// TODO: should this be typed with `extends BaseRequest/BaseResponse`?
|
// TODO: should this be typed with `extends BaseRequest/BaseResponse`?
|
||||||
return this.connection.request({
|
return this.connection.request({
|
||||||
...r,
|
...r,
|
||||||
// @ts-ignore
|
// @ts-expect-error
|
||||||
account: r.account ? ensureClassicAddress(r.account) : undefined,
|
account: r.account ? ensureClassicAddress(r.account) : undefined,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -258,38 +267,64 @@ class Client extends EventEmitter {
|
|||||||
* When there are more results than contained in the response, the response
|
* When there are more results than contained in the response, the response
|
||||||
* includes a `marker` field.
|
* includes a `marker` field.
|
||||||
*
|
*
|
||||||
* See https://ripple.com/build/rippled-apis/#markers-and-pagination
|
* See https://ripple.com/build/rippled-apis/#markers-and-pagination.
|
||||||
|
*
|
||||||
|
* @param response
|
||||||
*/
|
*/
|
||||||
hasNextPage(response: MarkerResponse): boolean {
|
hasNextPage(response: MarkerResponse): boolean {
|
||||||
return !!response.result.marker
|
return Boolean(response.result.marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
async requestNextPage(req: AccountChannelsRequest, resp: AccountChannelsResponse): Promise<AccountChannelsResponse>
|
async requestNextPage(
|
||||||
async requestNextPage(req: AccountLinesRequest, resp: AccountLinesResponse): Promise<AccountLinesResponse>
|
req: AccountChannelsRequest,
|
||||||
async requestNextPage(req: AccountObjectsRequest, resp: AccountObjectsResponse): Promise<AccountObjectsResponse>
|
resp: AccountChannelsResponse
|
||||||
async requestNextPage(req: AccountOffersRequest, resp: AccountOffersResponse): Promise<AccountOffersResponse>
|
): Promise<AccountChannelsResponse>;
|
||||||
async requestNextPage(req: AccountTxRequest, resp: AccountTxResponse): Promise<AccountTxResponse>
|
async requestNextPage(
|
||||||
async requestNextPage(req: LedgerDataRequest, resp: LedgerDataResponse): Promise<LedgerDataResponse>
|
req: AccountLinesRequest,
|
||||||
async requestNextPage<T extends MarkerRequest, U extends MarkerResponse>(req: T, resp: U): Promise<U> {
|
resp: AccountLinesResponse
|
||||||
|
): Promise<AccountLinesResponse>;
|
||||||
|
async requestNextPage(
|
||||||
|
req: AccountObjectsRequest,
|
||||||
|
resp: AccountObjectsResponse
|
||||||
|
): Promise<AccountObjectsResponse>;
|
||||||
|
async requestNextPage(
|
||||||
|
req: AccountOffersRequest,
|
||||||
|
resp: AccountOffersResponse
|
||||||
|
): Promise<AccountOffersResponse>;
|
||||||
|
async requestNextPage(
|
||||||
|
req: AccountTxRequest,
|
||||||
|
resp: AccountTxResponse
|
||||||
|
): Promise<AccountTxResponse>;
|
||||||
|
async requestNextPage(
|
||||||
|
req: LedgerDataRequest,
|
||||||
|
resp: LedgerDataResponse
|
||||||
|
): Promise<LedgerDataResponse>;
|
||||||
|
async requestNextPage<T extends MarkerRequest, U extends MarkerResponse>(
|
||||||
|
req: T,
|
||||||
|
resp: U
|
||||||
|
): Promise<U> {
|
||||||
if (!resp.result.marker) {
|
if (!resp.result.marker) {
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
new errors.NotFoundError('response does not have a next page')
|
new errors.NotFoundError("response does not have a next page")
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
const nextPageRequest = {...req, marker: resp.result.marker}
|
const nextPageRequest = { ...req, marker: resp.result.marker };
|
||||||
return this.connection.request(nextPageRequest)
|
return this.connection.request(nextPageRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare a transaction.
|
* Prepare a transaction.
|
||||||
*
|
*
|
||||||
* You can later submit the transaction with a `submit` request.
|
* You can later submit the transaction with a `submit` request.
|
||||||
|
*
|
||||||
|
* @param txJSON
|
||||||
|
* @param instructions
|
||||||
*/
|
*/
|
||||||
async prepareTransaction(
|
async prepareTransaction(
|
||||||
txJSON: TransactionJSON,
|
txJSON: TransactionJSON,
|
||||||
instructions: Instructions = {}
|
instructions: Instructions = {}
|
||||||
): Promise<Prepare> {
|
): Promise<Prepare> {
|
||||||
return transactionUtils.prepareTransaction(txJSON, this, instructions)
|
return transactionUtils.prepareTransaction(txJSON, this, instructions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -297,15 +332,15 @@ class Client extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* This can be used to generate `MemoData`, `MemoType`, and `MemoFormat`.
|
* This can be used to generate `MemoData`, `MemoType`, and `MemoFormat`.
|
||||||
*
|
*
|
||||||
* @param string string to convert to hex
|
* @param string - String to convert to hex.
|
||||||
*/
|
*/
|
||||||
convertStringToHex(string: string): string {
|
convertStringToHex(string: string): string {
|
||||||
return transactionUtils.convertStringToHex(string)
|
return transactionUtils.convertStringToHex(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes multiple paged requests to the client to return a given number of
|
* Makes multiple paged requests to the client to return a given number of
|
||||||
* resources. requestAll() will make multiple requests until the `limit`
|
* resources. Multiple paged requests will be made until the `limit`
|
||||||
* number of resources is reached (if no `limit` is provided, a single request
|
* number of resources is reached (if no `limit` is provided, a single request
|
||||||
* will be made).
|
* will be made).
|
||||||
*
|
*
|
||||||
@@ -316,129 +351,136 @@ class Client extends EventEmitter {
|
|||||||
* general use. Instead, use rippled's built-in pagination and make multiple
|
* general use. Instead, use rippled's built-in pagination and make multiple
|
||||||
* requests as needed.
|
* requests as needed.
|
||||||
*/
|
*/
|
||||||
async requestAll(req: AccountChannelsRequest): Promise<AccountChannelsResponse[]>
|
async requestAll(
|
||||||
async requestAll(req: AccountLinesRequest): Promise<AccountLinesResponse[]>
|
req: AccountChannelsRequest
|
||||||
async requestAll(req: AccountObjectsRequest): Promise<AccountObjectsResponse[]>
|
): Promise<AccountChannelsResponse[]>;
|
||||||
async requestAll(req: AccountOffersRequest): Promise<AccountOffersResponse[]>
|
async requestAll(req: AccountLinesRequest): Promise<AccountLinesResponse[]>;
|
||||||
async requestAll(req: AccountTxRequest): Promise<AccountTxResponse[]>
|
async requestAll(
|
||||||
async requestAll(req: BookOffersRequest): Promise<BookOffersResponse[]>
|
req: AccountObjectsRequest
|
||||||
async requestAll(req: LedgerDataRequest): Promise<LedgerDataResponse[]>
|
): Promise<AccountObjectsResponse[]>;
|
||||||
async requestAll<T extends MarkerRequest, U extends MarkerResponse>(request: T, options: {collect?: string} = {}): Promise<U[]> {
|
async requestAll(req: AccountOffersRequest): Promise<AccountOffersResponse[]>;
|
||||||
|
async requestAll(req: AccountTxRequest): Promise<AccountTxResponse[]>;
|
||||||
|
async requestAll(req: BookOffersRequest): Promise<BookOffersResponse[]>;
|
||||||
|
async requestAll(req: LedgerDataRequest): Promise<LedgerDataResponse[]>;
|
||||||
|
async requestAll<T extends MarkerRequest, U extends MarkerResponse>(
|
||||||
|
request: T,
|
||||||
|
options: { collect?: string } = {}
|
||||||
|
): Promise<U[]> {
|
||||||
// The data under collection is keyed based on the command. Fail if command
|
// The data under collection is keyed based on the command. Fail if command
|
||||||
// not recognized and collection key not provided.
|
// not recognized and collection key not provided.
|
||||||
const collectKey = options.collect || getCollectKeyFromCommand(request.command)
|
const collectKey =
|
||||||
|
options.collect || getCollectKeyFromCommand(request.command);
|
||||||
if (!collectKey) {
|
if (!collectKey) {
|
||||||
throw new errors.ValidationError(`no collect key for command ${request.command}`)
|
throw new errors.ValidationError(
|
||||||
|
`no collect key for command ${request.command}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// If limit is not provided, fetches all data over multiple requests.
|
// If limit is not provided, fetches all data over multiple requests.
|
||||||
// NOTE: This may return much more than needed. Set limit when possible.
|
// NOTE: This may return much more than needed. Set limit when possible.
|
||||||
const countTo: number = request.limit != null ? request.limit : Infinity
|
const countTo: number = request.limit != null ? request.limit : Infinity;
|
||||||
let count: number = 0
|
let count = 0;
|
||||||
let marker: string = request.marker
|
let marker: string = request.marker;
|
||||||
let lastBatchLength: number
|
let lastBatchLength: number;
|
||||||
const results = []
|
const results: any[] = [];
|
||||||
do {
|
do {
|
||||||
const countRemaining = clamp(countTo - count, 10, 400)
|
const countRemaining = clamp(countTo - count, 10, 400);
|
||||||
const repeatProps = {
|
const repeatProps = {
|
||||||
...request,
|
...request,
|
||||||
limit: countRemaining,
|
limit: countRemaining,
|
||||||
marker
|
marker,
|
||||||
}
|
};
|
||||||
const singleResponse = await this.connection.request(repeatProps)
|
const singleResponse = await this.connection.request(repeatProps);
|
||||||
const singleResult = singleResponse.result
|
const singleResult = singleResponse.result;
|
||||||
const collectedData = singleResult[collectKey]
|
const collectedData = singleResult[collectKey];
|
||||||
marker = singleResult['marker']
|
marker = singleResult.marker;
|
||||||
results.push(singleResponse)
|
results.push(singleResponse);
|
||||||
// Make sure we handle when no data (not even an empty array) is returned.
|
// Make sure we handle when no data (not even an empty array) is returned.
|
||||||
const isExpectedFormat = Array.isArray(collectedData)
|
const isExpectedFormat = Array.isArray(collectedData);
|
||||||
if (isExpectedFormat) {
|
if (isExpectedFormat) {
|
||||||
count += collectedData.length
|
count += collectedData.length;
|
||||||
lastBatchLength = collectedData.length
|
lastBatchLength = collectedData.length;
|
||||||
} else {
|
} else {
|
||||||
lastBatchLength = 0
|
lastBatchLength = 0;
|
||||||
}
|
}
|
||||||
} while (!!marker && count < countTo && lastBatchLength !== 0)
|
} while (Boolean(marker) && count < countTo && lastBatchLength !== 0);
|
||||||
return results
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConnected(): boolean {
|
isConnected(): boolean {
|
||||||
return this.connection.isConnected()
|
return this.connection.isConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(): Promise<void> {
|
async connect(): Promise<void> {
|
||||||
return this.connection.connect()
|
return this.connection.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
async disconnect(): Promise<void> {
|
async disconnect(): Promise<void> {
|
||||||
// backwards compatibility: connection.disconnect() can return a number, but
|
// backwards compatibility: connection.disconnect() can return a number, but
|
||||||
// this method returns nothing. SO we await but don't return any result.
|
// this method returns nothing. SO we await but don't return any result.
|
||||||
await this.connection.disconnect()
|
await this.connection.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
getFee = getFee
|
getFee = getFee;
|
||||||
|
|
||||||
getTrustlines = getTrustlines
|
getTrustlines = getTrustlines;
|
||||||
getBalances = getBalances
|
getBalances = getBalances;
|
||||||
getPaths = getPaths
|
getPaths = getPaths;
|
||||||
getOrderbook = getOrderbook
|
getOrderbook = getOrderbook;
|
||||||
|
|
||||||
preparePayment = preparePayment
|
preparePayment = preparePayment;
|
||||||
prepareTrustline = prepareTrustline
|
prepareTrustline = prepareTrustline;
|
||||||
prepareOrder = prepareOrder
|
prepareOrder = prepareOrder;
|
||||||
prepareOrderCancellation = prepareOrderCancellation
|
prepareOrderCancellation = prepareOrderCancellation;
|
||||||
prepareEscrowCreation = prepareEscrowCreation
|
prepareEscrowCreation = prepareEscrowCreation;
|
||||||
prepareEscrowExecution = prepareEscrowExecution
|
prepareEscrowExecution = prepareEscrowExecution;
|
||||||
prepareEscrowCancellation = prepareEscrowCancellation
|
prepareEscrowCancellation = prepareEscrowCancellation;
|
||||||
preparePaymentChannelCreate = preparePaymentChannelCreate
|
preparePaymentChannelCreate = preparePaymentChannelCreate;
|
||||||
preparePaymentChannelFund = preparePaymentChannelFund
|
preparePaymentChannelFund = preparePaymentChannelFund;
|
||||||
preparePaymentChannelClaim = preparePaymentChannelClaim
|
preparePaymentChannelClaim = preparePaymentChannelClaim;
|
||||||
prepareCheckCreate = prepareCheckCreate
|
prepareCheckCreate = prepareCheckCreate;
|
||||||
prepareCheckCash = prepareCheckCash
|
prepareCheckCash = prepareCheckCash;
|
||||||
prepareCheckCancel = prepareCheckCancel
|
prepareCheckCancel = prepareCheckCancel;
|
||||||
prepareTicketCreate = prepareTicketCreate
|
prepareTicketCreate = prepareTicketCreate;
|
||||||
prepareSettings = prepareSettings
|
prepareSettings = prepareSettings;
|
||||||
sign = sign
|
sign = sign;
|
||||||
combine = combine
|
combine = combine;
|
||||||
|
|
||||||
generateFaucetWallet = generateFaucetWallet
|
generateFaucetWallet = generateFaucetWallet;
|
||||||
|
|
||||||
errors = errors
|
errors = errors;
|
||||||
|
|
||||||
static deriveXAddress = deriveXAddress
|
static deriveXAddress = deriveXAddress;
|
||||||
|
|
||||||
// Client.deriveClassicAddress (static) is a new name for client.deriveAddress
|
// Client.deriveClassicAddress (static) is a new name for client.deriveAddress
|
||||||
static deriveClassicAddress = deriveAddress
|
static deriveClassicAddress = deriveAddress;
|
||||||
|
|
||||||
static formatBidsAndAsks = formatBidsAndAsks
|
static formatBidsAndAsks = formatBidsAndAsks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static methods to expose ripple-address-codec methods
|
* Static methods to expose ripple-address-codec methods.
|
||||||
*/
|
*/
|
||||||
static classicAddressToXAddress = classicAddressToXAddress
|
static classicAddressToXAddress = classicAddressToXAddress;
|
||||||
static xAddressToClassicAddress = xAddressToClassicAddress
|
static xAddressToClassicAddress = xAddressToClassicAddress;
|
||||||
static isValidXAddress = isValidXAddress
|
static isValidXAddress = isValidXAddress;
|
||||||
static isValidClassicAddress = isValidClassicAddress
|
static isValidClassicAddress = isValidClassicAddress;
|
||||||
static encodeSeed = encodeSeed
|
static encodeSeed = encodeSeed;
|
||||||
static decodeSeed = decodeSeed
|
static decodeSeed = decodeSeed;
|
||||||
static encodeAccountID = encodeAccountID
|
static encodeAccountID = encodeAccountID;
|
||||||
static decodeAccountID = decodeAccountID
|
static decodeAccountID = decodeAccountID;
|
||||||
static encodeNodePublic = encodeNodePublic
|
static encodeNodePublic = encodeNodePublic;
|
||||||
static decodeNodePublic = decodeNodePublic
|
static decodeNodePublic = decodeNodePublic;
|
||||||
static encodeAccountPublic = encodeAccountPublic
|
static encodeAccountPublic = encodeAccountPublic;
|
||||||
static decodeAccountPublic = decodeAccountPublic
|
static decodeAccountPublic = decodeAccountPublic;
|
||||||
static encodeXAddress = encodeXAddress
|
static encodeXAddress = encodeXAddress;
|
||||||
static decodeXAddress = decodeXAddress
|
static decodeXAddress = decodeXAddress;
|
||||||
|
|
||||||
txFlags = txFlags
|
txFlags = txFlags;
|
||||||
static txFlags = txFlags
|
static txFlags = txFlags;
|
||||||
accountSetFlags = constants.AccountSetFlags
|
accountSetFlags = constants.AccountSetFlags;
|
||||||
static accountSetFlags = constants.AccountSetFlags
|
static accountSetFlags = constants.AccountSetFlags;
|
||||||
|
|
||||||
isValidAddress = schemaValidator.isValidAddress
|
isValidAddress = schemaValidator.isValidAddress;
|
||||||
isValidSecret = schemaValidator.isValidSecret
|
isValidSecret = schemaValidator.isValidSecret;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { Client, Connection };
|
||||||
Client,
|
|
||||||
Connection
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,63 +1,64 @@
|
|||||||
import * as _ from 'lodash'
|
import * as assert from "assert";
|
||||||
import * as assert from 'assert'
|
|
||||||
|
|
||||||
type Interval = [number, number]
|
import * as _ from "lodash";
|
||||||
|
|
||||||
|
type Interval = [number, number];
|
||||||
|
|
||||||
function mergeIntervals(intervals: Interval[]): Interval[] {
|
function mergeIntervals(intervals: Interval[]): Interval[] {
|
||||||
const stack: Interval[] = [[-Infinity, -Infinity]]
|
const stack: Interval[] = [[-Infinity, -Infinity]];
|
||||||
_.sortBy(intervals, (x) => x[0]).forEach((interval) => {
|
_.sortBy(intervals, (x) => x[0]).forEach((interval) => {
|
||||||
const lastInterval: Interval = stack.pop()!
|
const lastInterval: Interval = stack.pop()!;
|
||||||
if (interval[0] <= lastInterval[1] + 1) {
|
if (interval[0] <= lastInterval[1] + 1) {
|
||||||
stack.push([lastInterval[0], Math.max(interval[1], lastInterval[1])])
|
stack.push([lastInterval[0], Math.max(interval[1], lastInterval[1])]);
|
||||||
} else {
|
} else {
|
||||||
stack.push(lastInterval)
|
stack.push(lastInterval);
|
||||||
stack.push(interval)
|
stack.push(interval);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return stack.slice(1)
|
return stack.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
class RangeSet {
|
class RangeSet {
|
||||||
ranges: Array<[number, number]>
|
ranges: Array<[number, number]> = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.reset()
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.ranges = []
|
this.ranges = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize() {
|
serialize() {
|
||||||
return this.ranges
|
return this.ranges
|
||||||
.map((range) => range[0].toString() + '-' + range[1].toString())
|
.map((range) => `${range[0].toString()}-${range[1].toString()}`)
|
||||||
.join(',')
|
.join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
addRange(start: number, end: number) {
|
addRange(start: number, end: number) {
|
||||||
assert.ok(start <= end, `invalid range ${start} <= ${end}`)
|
assert.ok(start <= end, `invalid range ${start} <= ${end}`);
|
||||||
this.ranges = mergeIntervals(this.ranges.concat([[start, end]]))
|
this.ranges = mergeIntervals(this.ranges.concat([[start, end]]));
|
||||||
}
|
}
|
||||||
|
|
||||||
addValue(value: number) {
|
addValue(value: number) {
|
||||||
this.addRange(value, value)
|
this.addRange(value, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseAndAddRanges(rangesString: string) {
|
parseAndAddRanges(rangesString: string) {
|
||||||
const rangeStrings = rangesString.split(',')
|
const rangeStrings = rangesString.split(",");
|
||||||
rangeStrings.forEach((rangeString) => {
|
rangeStrings.forEach((rangeString) => {
|
||||||
const range = rangeString.split('-').map(Number)
|
const range = rangeString.split("-").map(Number);
|
||||||
this.addRange(range[0], range.length === 1 ? range[0] : range[1])
|
this.addRange(range[0], range.length === 1 ? range[0] : range[1]);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
containsRange(start: number, end: number) {
|
containsRange(start: number, end: number) {
|
||||||
return this.ranges.some((range) => range[0] <= start && range[1] >= end)
|
return this.ranges.some((range) => range[0] <= start && range[1] >= end);
|
||||||
}
|
}
|
||||||
|
|
||||||
containsValue(value: number) {
|
containsValue(value: number) {
|
||||||
return this.containsRange(value, value)
|
return this.containsRange(value, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RangeSet
|
export default RangeSet;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import {EventEmitter} from 'events'
|
import { EventEmitter } from "events";
|
||||||
|
|
||||||
// Define the global WebSocket class found on the native browser
|
// Define the global WebSocket class found on the native browser
|
||||||
declare class WebSocket {
|
declare class WebSocket {
|
||||||
onclose?: Function
|
onclose?: Function;
|
||||||
onopen?: Function
|
onopen?: Function;
|
||||||
onerror?: Function
|
onerror?: Function;
|
||||||
onmessage?: Function
|
onmessage?: Function;
|
||||||
readyState: number
|
readyState: number;
|
||||||
constructor(url: string)
|
constructor(url: string);
|
||||||
close()
|
close();
|
||||||
send(message: string)
|
send(message: string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,46 +17,46 @@ declare class WebSocket {
|
|||||||
* same, as `ws` package provides.
|
* same, as `ws` package provides.
|
||||||
*/
|
*/
|
||||||
export default class WSWrapper extends EventEmitter {
|
export default class WSWrapper extends EventEmitter {
|
||||||
private _ws: WebSocket
|
private readonly _ws: WebSocket;
|
||||||
static CONNECTING = 0
|
static CONNECTING = 0;
|
||||||
static OPEN = 1
|
static OPEN = 1;
|
||||||
static CLOSING = 2
|
static CLOSING = 2;
|
||||||
static CLOSED = 3
|
static CLOSED = 3;
|
||||||
|
|
||||||
constructor(url, _protocols: any, _websocketOptions: any) {
|
constructor(url, _protocols: any, _websocketOptions: any) {
|
||||||
super()
|
super();
|
||||||
this.setMaxListeners(Infinity)
|
this.setMaxListeners(Infinity);
|
||||||
|
|
||||||
this._ws = new WebSocket(url)
|
this._ws = new WebSocket(url);
|
||||||
|
|
||||||
this._ws.onclose = () => {
|
this._ws.onclose = () => {
|
||||||
this.emit('close')
|
this.emit("close");
|
||||||
}
|
};
|
||||||
|
|
||||||
this._ws.onopen = () => {
|
this._ws.onopen = () => {
|
||||||
this.emit('open')
|
this.emit("open");
|
||||||
}
|
};
|
||||||
|
|
||||||
this._ws.onerror = (error) => {
|
this._ws.onerror = (error) => {
|
||||||
this.emit('error', error)
|
this.emit("error", error);
|
||||||
}
|
};
|
||||||
|
|
||||||
this._ws.onmessage = (message) => {
|
this._ws.onmessage = (message) => {
|
||||||
this.emit('message', message.data)
|
this.emit("message", message.data);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
if (this.readyState === 1) {
|
if (this.readyState === 1) {
|
||||||
this._ws.close()
|
this._ws.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
send(message) {
|
send(message) {
|
||||||
this._ws.send(message)
|
this._ws.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
get readyState() {
|
get readyState() {
|
||||||
return this._ws.readyState
|
return this._ws.readyState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {txFlagIndices} from './txflags'
|
import { txFlagIndices } from "./txflags";
|
||||||
|
|
||||||
// Ordering from https://developers.ripple.com/accountroot.html
|
// Ordering from https://developers.ripple.com/accountroot.html
|
||||||
const accountRootFlags = {
|
const accountRootFlags = {
|
||||||
@@ -43,8 +43,8 @@ const accountRootFlags = {
|
|||||||
|
|
||||||
// lsfRequireDestTag:
|
// lsfRequireDestTag:
|
||||||
// Require a DestinationTag for incoming payments.
|
// Require a DestinationTag for incoming payments.
|
||||||
RequireDestTag: 0x00020000
|
RequireDestTag: 0x00020000,
|
||||||
}
|
};
|
||||||
|
|
||||||
const AccountFlags = {
|
const AccountFlags = {
|
||||||
passwordSpent: accountRootFlags.PasswordSpent,
|
passwordSpent: accountRootFlags.PasswordSpent,
|
||||||
@@ -55,19 +55,19 @@ const AccountFlags = {
|
|||||||
disableMasterKey: accountRootFlags.DisableMaster,
|
disableMasterKey: accountRootFlags.DisableMaster,
|
||||||
noFreeze: accountRootFlags.NoFreeze,
|
noFreeze: accountRootFlags.NoFreeze,
|
||||||
globalFreeze: accountRootFlags.GlobalFreeze,
|
globalFreeze: accountRootFlags.GlobalFreeze,
|
||||||
defaultRipple: accountRootFlags.DefaultRipple
|
defaultRipple: accountRootFlags.DefaultRipple,
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface Settings {
|
export interface Settings {
|
||||||
passwordSpent?: boolean
|
passwordSpent?: boolean;
|
||||||
requireDestinationTag?: boolean
|
requireDestinationTag?: boolean;
|
||||||
requireAuthorization?: boolean
|
requireAuthorization?: boolean;
|
||||||
depositAuth?: boolean
|
depositAuth?: boolean;
|
||||||
disallowIncomingXRP?: boolean
|
disallowIncomingXRP?: boolean;
|
||||||
disableMasterKey?: boolean
|
disableMasterKey?: boolean;
|
||||||
noFreeze?: boolean
|
noFreeze?: boolean;
|
||||||
globalFreeze?: boolean
|
globalFreeze?: boolean;
|
||||||
defaultRipple?: boolean
|
defaultRipple?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AccountSetFlags = {
|
const AccountSetFlags = {
|
||||||
@@ -79,21 +79,21 @@ const AccountSetFlags = {
|
|||||||
enableTransactionIDTracking: txFlagIndices.AccountSet.asfAccountTxnID,
|
enableTransactionIDTracking: txFlagIndices.AccountSet.asfAccountTxnID,
|
||||||
noFreeze: txFlagIndices.AccountSet.asfNoFreeze,
|
noFreeze: txFlagIndices.AccountSet.asfNoFreeze,
|
||||||
globalFreeze: txFlagIndices.AccountSet.asfGlobalFreeze,
|
globalFreeze: txFlagIndices.AccountSet.asfGlobalFreeze,
|
||||||
defaultRipple: txFlagIndices.AccountSet.asfDefaultRipple
|
defaultRipple: txFlagIndices.AccountSet.asfDefaultRipple,
|
||||||
}
|
};
|
||||||
|
|
||||||
const AccountFields = {
|
const AccountFields = {
|
||||||
EmailHash: {
|
EmailHash: {
|
||||||
name: 'emailHash',
|
name: "emailHash",
|
||||||
encoding: 'hex',
|
encoding: "hex",
|
||||||
length: 32,
|
length: 32,
|
||||||
defaults: '00000000000000000000000000000000'
|
defaults: "00000000000000000000000000000000",
|
||||||
},
|
},
|
||||||
WalletLocator: {name: 'walletLocator'},
|
WalletLocator: { name: "walletLocator" },
|
||||||
MessageKey: {name: 'messageKey'},
|
MessageKey: { name: "messageKey" },
|
||||||
Domain: {name: 'domain', encoding: 'hex'},
|
Domain: { name: "domain", encoding: "hex" },
|
||||||
TransferRate: {name: 'transferRate', defaults: 0, shift: 9},
|
TransferRate: { name: "transferRate", defaults: 0, shift: 9 },
|
||||||
TickSize: {name: 'tickSize', defaults: 0}
|
TickSize: { name: "tickSize", defaults: 0 },
|
||||||
}
|
};
|
||||||
|
|
||||||
export {AccountFields, AccountSetFlags, AccountFlags}
|
export { AccountFields, AccountSetFlags, AccountFlags };
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
enum ECDSA {
|
enum ECDSA {
|
||||||
ed25519 = 'ed25519',
|
ed25519 = "ed25519",
|
||||||
secp256k1 = 'ecdsa-secp256k1',
|
secp256k1 = "ecdsa-secp256k1",
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ECDSA
|
export default ECDSA;
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
import {inspect} from 'util'
|
import { inspect } from "util";
|
||||||
|
|
||||||
class RippleError extends Error {
|
class RippleError extends Error {
|
||||||
name: string
|
name: string;
|
||||||
message: string
|
message: string;
|
||||||
data?: any
|
data?: any;
|
||||||
|
|
||||||
constructor(message = '', data?: any) {
|
constructor(message = "", data?: any) {
|
||||||
super(message)
|
super(message);
|
||||||
|
|
||||||
this.name = this.constructor.name
|
this.name = this.constructor.name;
|
||||||
this.message = message
|
this.message = message;
|
||||||
this.data = data
|
this.data = data;
|
||||||
if (Error.captureStackTrace) {
|
if (Error.captureStackTrace) {
|
||||||
Error.captureStackTrace(this, this.constructor)
|
Error.captureStackTrace(this, this.constructor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
let result = '[' + this.name + '(' + this.message
|
let result = `[${this.name}(${this.message}`;
|
||||||
if (this.data) {
|
if (this.data) {
|
||||||
result += ', ' + inspect(this.data)
|
result += `, ${inspect(this.data)}`;
|
||||||
}
|
}
|
||||||
result += ')]'
|
result += ")]";
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* console.log in node uses util.inspect on object, and util.inspect allows
|
// console.log in node uses util.inspect on object, and util.inspect allows
|
||||||
us to customize its output:
|
// us to customize its output:
|
||||||
https://nodejs.org/api/util.html#util_custom_inspect_function_on_objects */
|
// https://nodejs.org/api/util.html#util_custom_inspect_function_on_objects
|
||||||
inspect() {
|
inspect() {
|
||||||
return this.toString()
|
return this.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,14 +56,14 @@ class ValidationError extends RippleError {}
|
|||||||
class XRPLFaucetError extends RippleError {}
|
class XRPLFaucetError extends RippleError {}
|
||||||
|
|
||||||
class NotFoundError extends RippleError {
|
class NotFoundError extends RippleError {
|
||||||
constructor(message = 'Not found') {
|
constructor(message = "Not found") {
|
||||||
super(message)
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MissingLedgerHistoryError extends RippleError {
|
class MissingLedgerHistoryError extends RippleError {
|
||||||
constructor(message?: string) {
|
constructor(message?: string) {
|
||||||
super(message || 'Server is missing ledger history in the specified range')
|
super(message || "Server is missing ledger history in the specified range");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,8 +72,8 @@ class PendingLedgerVersionError extends RippleError {
|
|||||||
super(
|
super(
|
||||||
message ||
|
message ||
|
||||||
"maxLedgerVersion is greater than server's most recent" +
|
"maxLedgerVersion is greater than server's most recent" +
|
||||||
' validated ledger'
|
" validated ledger"
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,5 +92,5 @@ export {
|
|||||||
PendingLedgerVersionError,
|
PendingLedgerVersionError,
|
||||||
MissingLedgerHistoryError,
|
MissingLedgerHistoryError,
|
||||||
LedgerVersionError,
|
LedgerVersionError,
|
||||||
XRPLFaucetError
|
XRPLFaucetError,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,29 +1,38 @@
|
|||||||
import _ from 'lodash'
|
import BigNumber from "bignumber.js";
|
||||||
import BigNumber from 'bignumber.js'
|
import _ from "lodash";
|
||||||
import {Client} from '..'
|
|
||||||
|
import { Client } from "..";
|
||||||
|
|
||||||
// This is a public API that can be called directly.
|
// This is a public API that can be called directly.
|
||||||
// This is not used by the `prepare*` methods. See `src/transaction/utils.ts`
|
// This is not used by the `prepare*` methods. See `src/transaction/utils.ts`
|
||||||
async function getFee(this: Client, cushion?: number): Promise<string> {
|
async function getFee(this: Client, cushion?: number): Promise<string> {
|
||||||
if (cushion == null) {
|
if (cushion == null) {
|
||||||
cushion = this._feeCushion
|
cushion = this._feeCushion;
|
||||||
}
|
}
|
||||||
if (cushion == null) {
|
if (cushion == null) {
|
||||||
cushion = 1.2
|
cushion = 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverInfo = (await this.request({command: "server_info"})).result.info
|
const serverInfo = (await this.request({ command: "server_info" })).result
|
||||||
const baseFeeXrp = new BigNumber(serverInfo.validated_ledger.base_fee_xrp)
|
.info;
|
||||||
|
|
||||||
|
const baseFee = serverInfo.validated_ledger?.base_fee_xrp;
|
||||||
|
|
||||||
|
if (baseFee == null) {
|
||||||
|
throw new Error("getFee: Could not get base_fee_xrp from server_info");
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseFeeXrp = new BigNumber(baseFee);
|
||||||
if (serverInfo.load_factor == null) {
|
if (serverInfo.load_factor == null) {
|
||||||
// https://github.com/ripple/rippled/issues/3812#issuecomment-816871100
|
// https://github.com/ripple/rippled/issues/3812#issuecomment-816871100
|
||||||
serverInfo.load_factor = 1
|
serverInfo.load_factor = 1;
|
||||||
}
|
}
|
||||||
let fee = baseFeeXrp.times(serverInfo.load_factor).times(cushion)
|
let fee = baseFeeXrp.times(serverInfo.load_factor).times(cushion);
|
||||||
|
|
||||||
// Cap fee to `this._maxFeeXRP`
|
// Cap fee to `this._maxFeeXRP`
|
||||||
fee = BigNumber.min(fee, this._maxFeeXRP)
|
fee = BigNumber.min(fee, this._maxFeeXRP);
|
||||||
// Round fee to 6 decimal places
|
// Round fee to 6 decimal places
|
||||||
return new BigNumber(fee.toFixed(6)).toString(10)
|
return new BigNumber(fee.toFixed(6)).toString(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {getFee}
|
export { getFee };
|
||||||
|
|||||||
@@ -1,27 +1,30 @@
|
|||||||
import * as constants from './constants'
|
import {
|
||||||
import * as errors from './errors'
|
xAddressToClassicAddress,
|
||||||
import * as validate from './validate'
|
isValidXAddress,
|
||||||
import {xAddressToClassicAddress, isValidXAddress} from 'ripple-address-codec'
|
} from "ripple-address-codec";
|
||||||
|
|
||||||
|
import * as constants from "./constants";
|
||||||
|
import * as errors from "./errors";
|
||||||
|
import * as validate from "./validate";
|
||||||
|
|
||||||
export function ensureClassicAddress(account: string): string {
|
export function ensureClassicAddress(account: string): string {
|
||||||
if (isValidXAddress(account)) {
|
if (isValidXAddress(account)) {
|
||||||
const {classicAddress, tag} = xAddressToClassicAddress(account)
|
const { classicAddress, tag } = xAddressToClassicAddress(account);
|
||||||
|
|
||||||
// Except for special cases, X-addresses used for requests
|
// Except for special cases, X-addresses used for requests
|
||||||
// must not have an embedded tag. In other words,
|
// must not have an embedded tag. In other words,
|
||||||
// `tag` should be `false`.
|
// `tag` should be `false`.
|
||||||
if (tag !== false) {
|
if (tag !== false) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'This command does not support the use of a tag. Use an address without a tag.'
|
"This command does not support the use of a tag. Use an address without a tag."
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For rippled requests that use an account, always use a classic address.
|
// For rippled requests that use an account, always use a classic address.
|
||||||
return classicAddress
|
return classicAddress;
|
||||||
} else {
|
|
||||||
return account
|
|
||||||
}
|
}
|
||||||
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {constants, errors, validate}
|
export { constants, errors, validate };
|
||||||
export {txFlags} from './txflags'
|
export { txFlags } from "./txflags";
|
||||||
|
|||||||
@@ -1,134 +1,140 @@
|
|||||||
import _ from 'lodash'
|
import * as assert from "assert";
|
||||||
import * as assert from 'assert'
|
|
||||||
const {Validator} = require('jsonschema')
|
import _ from "lodash";
|
||||||
import {ValidationError} from './errors'
|
import { isValidClassicAddress, isValidXAddress } from "ripple-address-codec";
|
||||||
import {isValidClassicAddress, isValidXAddress} from 'ripple-address-codec'
|
|
||||||
import {isValidSecret} from '../utils'
|
import { isValidSecret } from "../utils";
|
||||||
|
|
||||||
|
import { ValidationError } from "./errors";
|
||||||
|
|
||||||
|
const { Validator } = require("jsonschema");
|
||||||
|
|
||||||
function loadSchemas() {
|
function loadSchemas() {
|
||||||
// listed explicitly for webpack (instead of scanning schemas directory)
|
// listed explicitly for webpack (instead of scanning schemas directory)
|
||||||
const schemas = [
|
const schemas = [
|
||||||
require('./schemas/objects/tx-json.json'),
|
require("./schemas/objects/tx-json.json"),
|
||||||
require('./schemas/objects/transaction-type.json'),
|
require("./schemas/objects/transaction-type.json"),
|
||||||
require('./schemas/objects/hash128.json'),
|
require("./schemas/objects/hash128.json"),
|
||||||
require('./schemas/objects/hash256.json'),
|
require("./schemas/objects/hash256.json"),
|
||||||
require('./schemas/objects/sequence.json'),
|
require("./schemas/objects/sequence.json"),
|
||||||
require('./schemas/objects/ticket-sequence.json'),
|
require("./schemas/objects/ticket-sequence.json"),
|
||||||
require('./schemas/objects/signature.json'),
|
require("./schemas/objects/signature.json"),
|
||||||
require('./schemas/objects/issue.json'),
|
require("./schemas/objects/issue.json"),
|
||||||
require('./schemas/objects/ledger-version.json'),
|
require("./schemas/objects/ledger-version.json"),
|
||||||
require('./schemas/objects/max-adjustment.json'),
|
require("./schemas/objects/max-adjustment.json"),
|
||||||
require('./schemas/objects/memo.json'),
|
require("./schemas/objects/memo.json"),
|
||||||
require('./schemas/objects/memos.json'),
|
require("./schemas/objects/memos.json"),
|
||||||
require('./schemas/objects/public-key.json'),
|
require("./schemas/objects/public-key.json"),
|
||||||
require('./schemas/objects/private-key.json'),
|
require("./schemas/objects/private-key.json"),
|
||||||
require('./schemas/objects/uint32.json'),
|
require("./schemas/objects/uint32.json"),
|
||||||
require('./schemas/objects/value.json'),
|
require("./schemas/objects/value.json"),
|
||||||
require('./schemas/objects/source-adjustment.json'),
|
require("./schemas/objects/source-adjustment.json"),
|
||||||
require('./schemas/objects/destination-adjustment.json'),
|
require("./schemas/objects/destination-adjustment.json"),
|
||||||
require('./schemas/objects/tag.json'),
|
require("./schemas/objects/tag.json"),
|
||||||
require('./schemas/objects/lax-amount.json'),
|
require("./schemas/objects/lax-amount.json"),
|
||||||
require('./schemas/objects/lax-lax-amount.json'),
|
require("./schemas/objects/lax-lax-amount.json"),
|
||||||
require('./schemas/objects/min-adjustment.json'),
|
require("./schemas/objects/min-adjustment.json"),
|
||||||
require('./schemas/objects/source-exact-adjustment.json'),
|
require("./schemas/objects/source-exact-adjustment.json"),
|
||||||
require('./schemas/objects/destination-exact-adjustment.json'),
|
require("./schemas/objects/destination-exact-adjustment.json"),
|
||||||
require('./schemas/objects/destination-address-tag.json'),
|
require("./schemas/objects/destination-address-tag.json"),
|
||||||
require('./schemas/objects/transaction-hash.json'),
|
require("./schemas/objects/transaction-hash.json"),
|
||||||
require('./schemas/objects/address.json'),
|
require("./schemas/objects/address.json"),
|
||||||
require('./schemas/objects/x-address.json'),
|
require("./schemas/objects/x-address.json"),
|
||||||
require('./schemas/objects/classic-address.json'),
|
require("./schemas/objects/classic-address.json"),
|
||||||
require('./schemas/objects/adjustment.json'),
|
require("./schemas/objects/adjustment.json"),
|
||||||
require('./schemas/objects/quality.json'),
|
require("./schemas/objects/quality.json"),
|
||||||
require('./schemas/objects/amount.json'),
|
require("./schemas/objects/amount.json"),
|
||||||
require('./schemas/objects/amountbase.json'),
|
require("./schemas/objects/amountbase.json"),
|
||||||
require('./schemas/objects/balance.json'),
|
require("./schemas/objects/balance.json"),
|
||||||
require('./schemas/objects/blob.json'),
|
require("./schemas/objects/blob.json"),
|
||||||
require('./schemas/objects/currency.json'),
|
require("./schemas/objects/currency.json"),
|
||||||
require('./schemas/objects/signed-value.json'),
|
require("./schemas/objects/signed-value.json"),
|
||||||
require('./schemas/objects/orderbook.json'),
|
require("./schemas/objects/orderbook.json"),
|
||||||
require('./schemas/objects/instructions.json'),
|
require("./schemas/objects/instructions.json"),
|
||||||
require('./schemas/objects/settings-plus-memos.json'),
|
require("./schemas/objects/settings-plus-memos.json"),
|
||||||
require('./schemas/specifications/settings.json'),
|
require("./schemas/specifications/settings.json"),
|
||||||
require('./schemas/specifications/payment.json'),
|
require("./schemas/specifications/payment.json"),
|
||||||
require('./schemas/specifications/get-payment.json'),
|
require("./schemas/specifications/get-payment.json"),
|
||||||
require('./schemas/specifications/escrow-cancellation.json'),
|
require("./schemas/specifications/escrow-cancellation.json"),
|
||||||
require('./schemas/specifications/order-cancellation.json'),
|
require("./schemas/specifications/order-cancellation.json"),
|
||||||
require('./schemas/specifications/order.json'),
|
require("./schemas/specifications/order.json"),
|
||||||
require('./schemas/specifications/escrow-execution.json'),
|
require("./schemas/specifications/escrow-execution.json"),
|
||||||
require('./schemas/specifications/escrow-creation.json'),
|
require("./schemas/specifications/escrow-creation.json"),
|
||||||
require('./schemas/specifications/payment-channel-create.json'),
|
require("./schemas/specifications/payment-channel-create.json"),
|
||||||
require('./schemas/specifications/payment-channel-fund.json'),
|
require("./schemas/specifications/payment-channel-fund.json"),
|
||||||
require('./schemas/specifications/payment-channel-claim.json'),
|
require("./schemas/specifications/payment-channel-claim.json"),
|
||||||
require('./schemas/specifications/check-create.json'),
|
require("./schemas/specifications/check-create.json"),
|
||||||
require('./schemas/specifications/check-cash.json'),
|
require("./schemas/specifications/check-cash.json"),
|
||||||
require('./schemas/specifications/check-cancel.json'),
|
require("./schemas/specifications/check-cancel.json"),
|
||||||
require('./schemas/specifications/trustline.json'),
|
require("./schemas/specifications/trustline.json"),
|
||||||
require('./schemas/specifications/deposit-preauth.json'),
|
require("./schemas/specifications/deposit-preauth.json"),
|
||||||
require('./schemas/specifications/account-delete.json'),
|
require("./schemas/specifications/account-delete.json"),
|
||||||
require('./schemas/output/sign.json'),
|
require("./schemas/output/sign.json"),
|
||||||
require('./schemas/output/submit.json'),
|
require("./schemas/output/submit.json"),
|
||||||
require('./schemas/output/get-account-info.json'),
|
require("./schemas/output/get-account-info.json"),
|
||||||
require('./schemas/output/get-account-objects.json'),
|
require("./schemas/output/get-account-objects.json"),
|
||||||
require('./schemas/output/get-balances.json'),
|
require("./schemas/output/get-balances.json"),
|
||||||
require('./schemas/output/get-balance-sheet.json'),
|
require("./schemas/output/get-balance-sheet.json"),
|
||||||
require('./schemas/output/get-ledger.json'),
|
require("./schemas/output/get-ledger.json"),
|
||||||
require('./schemas/output/get-orderbook.json'),
|
require("./schemas/output/get-orderbook.json"),
|
||||||
require('./schemas/output/get-orders.json'),
|
require("./schemas/output/get-orders.json"),
|
||||||
require('./schemas/output/order-change.json'),
|
require("./schemas/output/order-change.json"),
|
||||||
require('./schemas/output/get-payment-channel.json'),
|
require("./schemas/output/get-payment-channel.json"),
|
||||||
require('./schemas/output/prepare.json'),
|
require("./schemas/output/prepare.json"),
|
||||||
require('./schemas/output/ledger-event.json'),
|
require("./schemas/output/ledger-event.json"),
|
||||||
require('./schemas/output/get-paths.json'),
|
require("./schemas/output/get-paths.json"),
|
||||||
require('./schemas/output/get-server-info.json'),
|
require("./schemas/output/get-server-info.json"),
|
||||||
require('./schemas/output/get-settings.json'),
|
require("./schemas/output/get-settings.json"),
|
||||||
require('./schemas/output/orderbook-orders.json'),
|
require("./schemas/output/orderbook-orders.json"),
|
||||||
require('./schemas/output/outcome.json'),
|
require("./schemas/output/outcome.json"),
|
||||||
require('./schemas/output/get-transaction.json'),
|
require("./schemas/output/get-transaction.json"),
|
||||||
require('./schemas/output/get-transactions.json'),
|
require("./schemas/output/get-transactions.json"),
|
||||||
require('./schemas/output/get-trustlines.json'),
|
require("./schemas/output/get-trustlines.json"),
|
||||||
require('./schemas/output/sign-payment-channel-claim.json'),
|
require("./schemas/output/sign-payment-channel-claim.json"),
|
||||||
require('./schemas/output/verify-payment-channel-claim.json'),
|
require("./schemas/output/verify-payment-channel-claim.json"),
|
||||||
require('./schemas/input/get-balances.json'),
|
require("./schemas/input/get-balances.json"),
|
||||||
require('./schemas/input/get-balance-sheet.json'),
|
require("./schemas/input/get-balance-sheet.json"),
|
||||||
require('./schemas/input/get-ledger.json'),
|
require("./schemas/input/get-ledger.json"),
|
||||||
require('./schemas/input/get-orders.json'),
|
require("./schemas/input/get-orders.json"),
|
||||||
require('./schemas/input/get-orderbook.json'),
|
require("./schemas/input/get-orderbook.json"),
|
||||||
require('./schemas/input/get-paths.json'),
|
require("./schemas/input/get-paths.json"),
|
||||||
require('./schemas/input/get-payment-channel.json'),
|
require("./schemas/input/get-payment-channel.json"),
|
||||||
require('./schemas/input/api-options.json'),
|
require("./schemas/input/api-options.json"),
|
||||||
require('./schemas/input/get-settings.json'),
|
require("./schemas/input/get-settings.json"),
|
||||||
require('./schemas/input/get-account-info.json'),
|
require("./schemas/input/get-account-info.json"),
|
||||||
require('./schemas/input/get-account-objects.json'),
|
require("./schemas/input/get-account-objects.json"),
|
||||||
require('./schemas/input/get-transaction.json'),
|
require("./schemas/input/get-transaction.json"),
|
||||||
require('./schemas/input/get-transactions.json'),
|
require("./schemas/input/get-transactions.json"),
|
||||||
require('./schemas/input/get-trustlines.json'),
|
require("./schemas/input/get-trustlines.json"),
|
||||||
require('./schemas/input/prepare-payment.json'),
|
require("./schemas/input/prepare-payment.json"),
|
||||||
require('./schemas/input/prepare-order.json'),
|
require("./schemas/input/prepare-order.json"),
|
||||||
require('./schemas/input/prepare-trustline.json'),
|
require("./schemas/input/prepare-trustline.json"),
|
||||||
require('./schemas/input/prepare-order-cancellation.json'),
|
require("./schemas/input/prepare-order-cancellation.json"),
|
||||||
require('./schemas/input/prepare-settings.json'),
|
require("./schemas/input/prepare-settings.json"),
|
||||||
require('./schemas/input/prepare-escrow-creation.json'),
|
require("./schemas/input/prepare-escrow-creation.json"),
|
||||||
require('./schemas/input/prepare-escrow-cancellation.json'),
|
require("./schemas/input/prepare-escrow-cancellation.json"),
|
||||||
require('./schemas/input/prepare-escrow-execution.json'),
|
require("./schemas/input/prepare-escrow-execution.json"),
|
||||||
require('./schemas/input/prepare-payment-channel-create.json'),
|
require("./schemas/input/prepare-payment-channel-create.json"),
|
||||||
require('./schemas/input/prepare-payment-channel-fund.json'),
|
require("./schemas/input/prepare-payment-channel-fund.json"),
|
||||||
require('./schemas/input/prepare-payment-channel-claim.json'),
|
require("./schemas/input/prepare-payment-channel-claim.json"),
|
||||||
require('./schemas/input/prepare-check-create.json'),
|
require("./schemas/input/prepare-check-create.json"),
|
||||||
require('./schemas/input/prepare-check-cash.json'),
|
require("./schemas/input/prepare-check-cash.json"),
|
||||||
require('./schemas/input/prepare-check-cancel.json'),
|
require("./schemas/input/prepare-check-cancel.json"),
|
||||||
require('./schemas/input/prepare-ticket-create.json'),
|
require("./schemas/input/prepare-ticket-create.json"),
|
||||||
require('./schemas/input/compute-ledger-hash.json'),
|
require("./schemas/input/compute-ledger-hash.json"),
|
||||||
require('./schemas/input/sign.json'),
|
require("./schemas/input/sign.json"),
|
||||||
require('./schemas/input/submit.json'),
|
require("./schemas/input/submit.json"),
|
||||||
require('./schemas/input/generate-address.json'),
|
require("./schemas/input/generate-address.json"),
|
||||||
require('./schemas/input/sign-payment-channel-claim.json'),
|
require("./schemas/input/sign-payment-channel-claim.json"),
|
||||||
require('./schemas/input/verify-payment-channel-claim.json'),
|
require("./schemas/input/verify-payment-channel-claim.json"),
|
||||||
require('./schemas/input/combine.json')
|
require("./schemas/input/combine.json"),
|
||||||
]
|
];
|
||||||
const titles = schemas.map((schema) => schema.title)
|
const titles = schemas.map((schema) => schema.title);
|
||||||
const duplicates = Object.keys(_.pickBy(_.countBy(titles), (count) => count > 1))
|
const duplicates = Object.keys(
|
||||||
assert.ok(duplicates.length === 0, 'Duplicate schemas for: ' + duplicates)
|
_.pickBy(_.countBy(titles), (count) => count > 1)
|
||||||
const validator = new Validator()
|
);
|
||||||
|
assert.ok(duplicates.length === 0, `Duplicate schemas for: ${duplicates}`);
|
||||||
|
const validator = new Validator();
|
||||||
// Register custom format validators that ignore undefined instances
|
// Register custom format validators that ignore undefined instances
|
||||||
// since jsonschema will still call the format validator on a missing
|
// since jsonschema will still call the format validator on a missing
|
||||||
// (optional) property
|
// (optional) property
|
||||||
@@ -136,49 +142,47 @@ function loadSchemas() {
|
|||||||
// This relies on "format": "xAddress" in `x-address.json`!
|
// This relies on "format": "xAddress" in `x-address.json`!
|
||||||
validator.customFormats.xAddress = function (instance) {
|
validator.customFormats.xAddress = function (instance) {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return isValidXAddress(instance)
|
return isValidXAddress(instance);
|
||||||
}
|
};
|
||||||
|
|
||||||
// This relies on "format": "classicAddress" in `classic-address.json`!
|
// This relies on "format": "classicAddress" in `classic-address.json`!
|
||||||
validator.customFormats.classicAddress = function (instance) {
|
validator.customFormats.classicAddress = function (instance) {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return isValidAddress(instance)
|
return isValidAddress(instance);
|
||||||
}
|
};
|
||||||
|
|
||||||
validator.customFormats.secret = function (instance) {
|
validator.customFormats.secret = function (instance) {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return isValidSecret(instance)
|
return isValidSecret(instance);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Register under the root URI '/'
|
// Register under the root URI '/'
|
||||||
schemas.forEach((schema) =>
|
schemas.forEach((schema) => validator.addSchema(schema, `/${schema.title}`));
|
||||||
validator.addSchema(schema, '/' + schema.title)
|
return validator;
|
||||||
)
|
|
||||||
return validator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const schemaValidator = loadSchemas()
|
const schemaValidator = loadSchemas();
|
||||||
|
|
||||||
function schemaValidate(schemaName: string, object: any): void {
|
function schemaValidate(schemaName: string, object: any): void {
|
||||||
// Lookup under the root URI '/'
|
// Lookup under the root URI '/'
|
||||||
const schema = schemaValidator.getSchema('/' + schemaName)
|
const schema = schemaValidator.getSchema(`/${schemaName}`);
|
||||||
if (schema == null) {
|
if (schema == null) {
|
||||||
throw new ValidationError('no schema for ' + schemaName)
|
throw new ValidationError(`no schema for ${schemaName}`);
|
||||||
}
|
}
|
||||||
const result = schemaValidator.validate(object, schema)
|
const result = schemaValidator.validate(object, schema);
|
||||||
if (!result.valid) {
|
if (!result.valid) {
|
||||||
throw new ValidationError(result.errors.join())
|
throw new ValidationError(result.errors.join());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidAddress(address: string): boolean {
|
function isValidAddress(address: string): boolean {
|
||||||
return isValidXAddress(address) || isValidClassicAddress(address)
|
return isValidXAddress(address) || isValidClassicAddress(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {schemaValidate, isValidSecret, isValidAddress}
|
export { schemaValidate, isValidSecret, isValidAddress };
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const txFlags = {
|
const txFlags = {
|
||||||
// Universal flags can apply to any transaction type
|
// Universal flags can apply to any transaction type
|
||||||
Universal: {
|
Universal: {
|
||||||
FullyCanonicalSig: 0x80000000
|
FullyCanonicalSig: 0x80000000,
|
||||||
},
|
},
|
||||||
|
|
||||||
AccountSet: {
|
AccountSet: {
|
||||||
@@ -10,7 +10,7 @@ const txFlags = {
|
|||||||
RequireAuth: 0x00040000,
|
RequireAuth: 0x00040000,
|
||||||
OptionalAuth: 0x00080000,
|
OptionalAuth: 0x00080000,
|
||||||
DisallowXRP: 0x00100000,
|
DisallowXRP: 0x00100000,
|
||||||
AllowXRP: 0x00200000
|
AllowXRP: 0x00200000,
|
||||||
},
|
},
|
||||||
|
|
||||||
TrustSet: {
|
TrustSet: {
|
||||||
@@ -19,27 +19,27 @@ const txFlags = {
|
|||||||
SetNoRipple: 0x00020000,
|
SetNoRipple: 0x00020000,
|
||||||
ClearNoRipple: 0x00040000,
|
ClearNoRipple: 0x00040000,
|
||||||
SetFreeze: 0x00100000,
|
SetFreeze: 0x00100000,
|
||||||
ClearFreeze: 0x00200000
|
ClearFreeze: 0x00200000,
|
||||||
},
|
},
|
||||||
|
|
||||||
OfferCreate: {
|
OfferCreate: {
|
||||||
Passive: 0x00010000,
|
Passive: 0x00010000,
|
||||||
ImmediateOrCancel: 0x00020000,
|
ImmediateOrCancel: 0x00020000,
|
||||||
FillOrKill: 0x00040000,
|
FillOrKill: 0x00040000,
|
||||||
Sell: 0x00080000
|
Sell: 0x00080000,
|
||||||
},
|
},
|
||||||
|
|
||||||
Payment: {
|
Payment: {
|
||||||
NoRippleDirect: 0x00010000,
|
NoRippleDirect: 0x00010000,
|
||||||
PartialPayment: 0x00020000,
|
PartialPayment: 0x00020000,
|
||||||
LimitQuality: 0x00040000
|
LimitQuality: 0x00040000,
|
||||||
},
|
},
|
||||||
|
|
||||||
PaymentChannelClaim: {
|
PaymentChannelClaim: {
|
||||||
Renew: 0x00010000,
|
Renew: 0x00010000,
|
||||||
Close: 0x00020000
|
Close: 0x00020000,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
// The following are integer (as opposed to bit) flags
|
// The following are integer (as opposed to bit) flags
|
||||||
// that can be set for particular transactions in the
|
// that can be set for particular transactions in the
|
||||||
@@ -54,8 +54,8 @@ const txFlagIndices = {
|
|||||||
asfNoFreeze: 6,
|
asfNoFreeze: 6,
|
||||||
asfGlobalFreeze: 7,
|
asfGlobalFreeze: 7,
|
||||||
asfDefaultRipple: 8,
|
asfDefaultRipple: 8,
|
||||||
asfDepositAuth: 9
|
asfDepositAuth: 9,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export {txFlags, txFlagIndices}
|
export { txFlags, txFlagIndices };
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
import {
|
import {
|
||||||
AccountRootLedgerEntry,
|
AccountRootLedgerEntry,
|
||||||
SignerListLedgerEntry,
|
SignerListLedgerEntry,
|
||||||
QueueData
|
QueueData,
|
||||||
} from '../objects'
|
} from "../objects";
|
||||||
|
|
||||||
export interface AccountInfoRequest {
|
export interface AccountInfoRequest {
|
||||||
account: string
|
account: string;
|
||||||
strict?: boolean
|
strict?: boolean;
|
||||||
queue?: boolean
|
queue?: boolean;
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
ledger_index?: number | ("validated" | "closed" | "current");
|
||||||
signer_lists?: boolean
|
signer_lists?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountInfoResponse {
|
export interface AccountInfoResponse {
|
||||||
account_data: AccountRootLedgerEntry
|
account_data: AccountRootLedgerEntry;
|
||||||
signer_lists?: SignerListLedgerEntry[]
|
signer_lists?: SignerListLedgerEntry[];
|
||||||
ledger_current_index?: number
|
ledger_current_index?: number;
|
||||||
ledger_index?: number
|
ledger_index?: number;
|
||||||
queue_data?: QueueData
|
queue_data?: QueueData;
|
||||||
validated?: boolean
|
validated?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import {Trustline} from '../objects'
|
import { Trustline } from "../objects";
|
||||||
|
|
||||||
export interface AccountLinesRequest {
|
export interface AccountLinesRequest {
|
||||||
account: string
|
account: string;
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
ledger_index?: number | ("validated" | "closed" | "current");
|
||||||
peer?: string
|
peer?: string;
|
||||||
limit?: number
|
limit?: number;
|
||||||
marker?: any
|
marker?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountLinesResponse {
|
export interface AccountLinesResponse {
|
||||||
account: string
|
account: string;
|
||||||
lines: Trustline[]
|
lines: Trustline[];
|
||||||
ledger_current_index?: number
|
ledger_current_index?: number;
|
||||||
ledger_index?: number
|
ledger_index?: number;
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
marker?: any
|
marker?: any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AccountObjectType } from '../../../models/common';
|
import { AccountObjectType } from "../../../models/common";
|
||||||
import {
|
import {
|
||||||
CheckLedgerEntry,
|
CheckLedgerEntry,
|
||||||
RippleStateLedgerEntry,
|
RippleStateLedgerEntry,
|
||||||
@@ -6,46 +6,46 @@ import {
|
|||||||
SignerListLedgerEntry,
|
SignerListLedgerEntry,
|
||||||
EscrowLedgerEntry,
|
EscrowLedgerEntry,
|
||||||
PayChannelLedgerEntry,
|
PayChannelLedgerEntry,
|
||||||
DepositPreauthLedgerEntry
|
DepositPreauthLedgerEntry,
|
||||||
} from '../objects'
|
} from "../objects";
|
||||||
|
|
||||||
export interface GetAccountObjectsOptions {
|
export interface GetAccountObjectsOptions {
|
||||||
type?: AccountObjectType
|
type?: AccountObjectType;
|
||||||
ledgerHash?: string
|
ledgerHash?: string;
|
||||||
ledgerIndex?: number | ('validated' | 'closed' | 'current')
|
ledgerIndex?: number | ("validated" | "closed" | "current");
|
||||||
limit?: number
|
limit?: number;
|
||||||
marker?: string
|
marker?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountObjectsRequest {
|
export interface AccountObjectsRequest {
|
||||||
account: string
|
account: string;
|
||||||
|
|
||||||
// (Optional) Filter results to include only this type of ledger object.
|
// (Optional) Filter results to include only this type of ledger object.
|
||||||
type?:
|
type?:
|
||||||
| string
|
| string
|
||||||
| (
|
| (
|
||||||
| 'check'
|
| "check"
|
||||||
| 'escrow'
|
| "escrow"
|
||||||
| 'offer'
|
| "offer"
|
||||||
| 'payment_channel'
|
| "payment_channel"
|
||||||
| 'signer_list'
|
| "signer_list"
|
||||||
| 'state'
|
| "state"
|
||||||
)
|
);
|
||||||
|
|
||||||
// (Optional) A 20-byte hex string for the ledger version to use.
|
// (Optional) A 20-byte hex string for the ledger version to use.
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
|
|
||||||
// (Optional) The sequence number of the ledger to use,
|
// (Optional) The sequence number of the ledger to use,
|
||||||
// or a shortcut string to choose a ledger automatically.
|
// or a shortcut string to choose a ledger automatically.
|
||||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
ledger_index?: number | ("validated" | "closed" | "current");
|
||||||
|
|
||||||
limit?: number
|
limit?: number;
|
||||||
|
|
||||||
marker?: string
|
marker?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountObjectsResponse {
|
export interface AccountObjectsResponse {
|
||||||
account: string
|
account: string;
|
||||||
|
|
||||||
// Array of objects owned by this account.
|
// Array of objects owned by this account.
|
||||||
// from the getAccountObjects section of the dev center
|
// from the getAccountObjects section of the dev center
|
||||||
@@ -57,29 +57,29 @@ export interface AccountObjectsResponse {
|
|||||||
| EscrowLedgerEntry
|
| EscrowLedgerEntry
|
||||||
| PayChannelLedgerEntry
|
| PayChannelLedgerEntry
|
||||||
| DepositPreauthLedgerEntry
|
| DepositPreauthLedgerEntry
|
||||||
>
|
>;
|
||||||
|
|
||||||
// (May be omitted) The identifying hash of the ledger
|
// (May be omitted) The identifying hash of the ledger
|
||||||
// that was used to generate this response.
|
// that was used to generate this response.
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
|
|
||||||
// (May be omitted) The sequence number of the ledger version
|
// (May be omitted) The sequence number of the ledger version
|
||||||
// that was used to generate this response.
|
// that was used to generate this response.
|
||||||
ledger_index?: number
|
ledger_index?: number;
|
||||||
|
|
||||||
// (May be omitted) The sequence number of the current in-progress ledger
|
// (May be omitted) The sequence number of the current in-progress ledger
|
||||||
// version that was used to generate this response.
|
// version that was used to generate this response.
|
||||||
ledger_current_index?: number
|
ledger_current_index?: number;
|
||||||
|
|
||||||
// The limit that was used in this request, if any.
|
// The limit that was used in this request, if any.
|
||||||
limit?: number
|
limit?: number;
|
||||||
|
|
||||||
// Server-defined value indicating the response is paginated. Pass this
|
// Server-defined value indicating the response is paginated. Pass this
|
||||||
// to the next call to resume where this call left off. Omitted when there
|
// to the next call to resume where this call left off. Omitted when there
|
||||||
// are no additional pages after this one.
|
// are no additional pages after this one.
|
||||||
marker?: string
|
marker?: string;
|
||||||
|
|
||||||
// If true, this information comes from a ledger version
|
// If true, this information comes from a ledger version
|
||||||
// that has been validated by consensus.
|
// that has been validated by consensus.
|
||||||
validated?: boolean
|
validated?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
import {RippledAmount} from '../objects'
|
import { RippledAmount } from "../objects";
|
||||||
|
|
||||||
export interface AccountOffersRequest {
|
export interface AccountOffersRequest {
|
||||||
account: string
|
account: string;
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
ledger_index?: number | ("validated" | "closed" | "current");
|
||||||
limit?: number
|
limit?: number;
|
||||||
marker?: any
|
marker?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountOffersResponse {
|
export interface AccountOffersResponse {
|
||||||
account: string
|
account: string;
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_current_index?: number
|
ledger_current_index?: number;
|
||||||
ledger_index?: number
|
ledger_index?: number;
|
||||||
marker?: any
|
marker?: any;
|
||||||
offers?: AccountOffer[]
|
offers?: AccountOffer[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountOffer {
|
export interface AccountOffer {
|
||||||
seq: number
|
seq: number;
|
||||||
flags: number
|
flags: number;
|
||||||
taker_gets: RippledAmount
|
taker_gets: RippledAmount;
|
||||||
taker_pays: RippledAmount
|
taker_pays: RippledAmount;
|
||||||
quality: string
|
quality: string;
|
||||||
expiration?: number
|
expiration?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,30 @@
|
|||||||
import {TakerRequestAmount, RippledAmount, OfferLedgerEntry} from '../objects'
|
import {
|
||||||
|
TakerRequestAmount,
|
||||||
|
RippledAmount,
|
||||||
|
OfferLedgerEntry,
|
||||||
|
} from "../objects";
|
||||||
|
|
||||||
export interface BookOffersRequest {
|
export interface BookOffersRequest {
|
||||||
taker?: string
|
taker?: string;
|
||||||
taker_gets: TakerRequestAmount
|
taker_gets: TakerRequestAmount;
|
||||||
taker_pays: TakerRequestAmount
|
taker_pays: TakerRequestAmount;
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
ledger_index?: number | ("validated" | "closed" | "current");
|
||||||
limit?: number
|
limit?: number;
|
||||||
marker?: any
|
marker?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BookOffersResponse {
|
export interface BookOffersResponse {
|
||||||
offers: BookOffer[]
|
offers: BookOffer[];
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_current_index?: number
|
ledger_current_index?: number;
|
||||||
ledger_index?: number
|
ledger_index?: number;
|
||||||
marker?: any
|
marker?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BookOffer extends OfferLedgerEntry {
|
export interface BookOffer extends OfferLedgerEntry {
|
||||||
quality?: string
|
quality?: string;
|
||||||
owner_funds?: string
|
owner_funds?: string;
|
||||||
taker_gets_funded?: RippledAmount
|
taker_gets_funded?: RippledAmount;
|
||||||
taker_pays_funded?: RippledAmount
|
taker_pays_funded?: RippledAmount;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import {Amount} from '../objects'
|
import { Amount } from "../objects";
|
||||||
|
|
||||||
export interface GatewayBalancesRequest {
|
export interface GatewayBalancesRequest {
|
||||||
account: string
|
account: string;
|
||||||
strict?: boolean
|
strict?: boolean;
|
||||||
hotwallet: string | Array<string>
|
hotwallet: string | string[];
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
ledger_index?: number | ("validated" | "closed" | "current");
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GatewayBalancesResponse {
|
export interface GatewayBalancesResponse {
|
||||||
account: string
|
account: string;
|
||||||
obligations?: {[currency: string]: string}
|
obligations?: { [currency: string]: string };
|
||||||
balances?: {[address: string]: Amount[]}
|
balances?: { [address: string]: Amount[] };
|
||||||
assets?: {[address: string]: Amount[]}
|
assets?: { [address: string]: Amount[] };
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_current_index?: number
|
ledger_current_index?: number;
|
||||||
ledger_index?: number
|
ledger_index?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
export * from './account_info'
|
export * from "./account_info";
|
||||||
export * from './account_lines'
|
export * from "./account_lines";
|
||||||
export * from './account_objects'
|
export * from "./account_objects";
|
||||||
export * from './account_offers'
|
export * from "./account_offers";
|
||||||
export * from './book_offers'
|
export * from "./book_offers";
|
||||||
export * from './gateway_balances'
|
export * from "./gateway_balances";
|
||||||
export * from './ledger'
|
export * from "./ledger";
|
||||||
export * from './ledger_data'
|
export * from "./ledger_data";
|
||||||
export * from './ledger_entry'
|
export * from "./ledger_entry";
|
||||||
export * from './server_info'
|
export * from "./server_info";
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import {Ledger, QueueData} from '../objects'
|
import { Ledger, QueueData } from "../objects";
|
||||||
|
|
||||||
export interface LedgerRequest {
|
export interface LedgerRequest {
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
ledger_index?: number | ("validated" | "closed" | "current");
|
||||||
full?: boolean
|
full?: boolean;
|
||||||
accounts?: boolean
|
accounts?: boolean;
|
||||||
transactions?: boolean
|
transactions?: boolean;
|
||||||
expand?: boolean
|
expand?: boolean;
|
||||||
owner_funds?: boolean
|
owner_funds?: boolean;
|
||||||
binary?: boolean
|
binary?: boolean;
|
||||||
queue?: boolean
|
queue?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LedgerResponse {
|
export interface LedgerResponse {
|
||||||
ledger_index: number
|
ledger_index: number;
|
||||||
ledger_hash: string
|
ledger_hash: string;
|
||||||
ledger: Ledger
|
ledger: Ledger;
|
||||||
queue_data?: QueueData
|
queue_data?: QueueData;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import {LedgerData} from '../objects'
|
import { LedgerData } from "../objects";
|
||||||
|
|
||||||
export interface LedgerDataRequest {
|
export interface LedgerDataRequest {
|
||||||
id?: any
|
id?: any;
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_index?: string
|
ledger_index?: string;
|
||||||
binary?: boolean
|
binary?: boolean;
|
||||||
limit?: number
|
limit?: number;
|
||||||
marker?: string
|
marker?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LedgerDataResponse = LedgerData
|
export type LedgerDataResponse = LedgerData;
|
||||||
|
|||||||
@@ -1,36 +1,36 @@
|
|||||||
import {LedgerEntry} from '../objects'
|
import { LedgerEntry } from "../objects";
|
||||||
|
|
||||||
export interface LedgerEntryRequest {
|
export interface LedgerEntryRequest {
|
||||||
ledger_hash?: string
|
ledger_hash?: string;
|
||||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
ledger_index?: number | ("validated" | "closed" | "current");
|
||||||
index?: string
|
index?: string;
|
||||||
account_root?: string
|
account_root?: string;
|
||||||
directory?:
|
directory?:
|
||||||
| string
|
| string
|
||||||
| {
|
| {
|
||||||
sub_index?: number
|
sub_index?: number;
|
||||||
dir_root: string
|
dir_root: string;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
sub_index?: number
|
sub_index?: number;
|
||||||
owner: string
|
owner: string;
|
||||||
}
|
};
|
||||||
offer?:
|
offer?:
|
||||||
| string
|
| string
|
||||||
| {
|
| {
|
||||||
account: string
|
account: string;
|
||||||
seq: number
|
seq: number;
|
||||||
}
|
};
|
||||||
ripple_state?: {
|
ripple_state?: {
|
||||||
accounts: [string, string]
|
accounts: [string, string];
|
||||||
currency: string
|
currency: string;
|
||||||
}
|
};
|
||||||
binary?: boolean
|
binary?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LedgerEntryResponse {
|
export interface LedgerEntryResponse {
|
||||||
index: string
|
index: string;
|
||||||
ledger_index: number
|
ledger_index: number;
|
||||||
node_binary?: string
|
node_binary?: string;
|
||||||
node?: LedgerEntry
|
node?: LedgerEntry;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
export interface ServerInfoRequest {
|
export interface ServerInfoRequest {
|
||||||
id?: number
|
id?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerInfoResponse {
|
export interface ServerInfoResponse {
|
||||||
info: {
|
info: {
|
||||||
amendment_blocked?: boolean
|
amendment_blocked?: boolean;
|
||||||
build_version: string
|
build_version: string;
|
||||||
closed_ledger?: LedgerInfo
|
closed_ledger?: LedgerInfo;
|
||||||
complete_ledgers: string
|
complete_ledgers: string;
|
||||||
hostid: string
|
hostid: string;
|
||||||
io_latency_ms: number
|
io_latency_ms: number;
|
||||||
last_close: {
|
last_close: {
|
||||||
converge_time_s: number
|
converge_time_s: number;
|
||||||
proposers: number
|
proposers: number;
|
||||||
}
|
};
|
||||||
load?: {
|
load?: {
|
||||||
job_types: {
|
job_types: Array<{
|
||||||
job_type: string
|
job_type: string;
|
||||||
per_second: number
|
per_second: number;
|
||||||
in_progress: number
|
in_progress: number;
|
||||||
}[]
|
}>;
|
||||||
threads: number
|
threads: number;
|
||||||
}
|
};
|
||||||
load_factor: number
|
load_factor: number;
|
||||||
load_factor_local?: number
|
load_factor_local?: number;
|
||||||
load_factor_net?: number
|
load_factor_net?: number;
|
||||||
load_factor_cluster?: number
|
load_factor_cluster?: number;
|
||||||
load_factor_fee_escalation?: number
|
load_factor_fee_escalation?: number;
|
||||||
load_factor_fee_queue?: number
|
load_factor_fee_queue?: number;
|
||||||
load_factor_server?: number
|
load_factor_server?: number;
|
||||||
peers: number
|
peers: number;
|
||||||
pubkey_node: string
|
pubkey_node: string;
|
||||||
pubkey_validator: string
|
pubkey_validator: string;
|
||||||
server_state: string
|
server_state: string;
|
||||||
state_accounting: any
|
state_accounting: any;
|
||||||
uptime: number
|
uptime: number;
|
||||||
validated_ledger?: LedgerInfo
|
validated_ledger?: LedgerInfo;
|
||||||
validation_quorum: number
|
validation_quorum: number;
|
||||||
validator_list_expires: string
|
validator_list_expires: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LedgerInfo {
|
export interface LedgerInfo {
|
||||||
age: number
|
age: number;
|
||||||
base_fee_xrp: number
|
base_fee_xrp: number;
|
||||||
hash: string
|
hash: string;
|
||||||
reserve_base_xrp: number
|
reserve_base_xrp: number;
|
||||||
reserve_inc_xrp: number
|
reserve_inc_xrp: number;
|
||||||
seq: number
|
seq: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import {Amount} from './amounts'
|
import { Amount } from "./amounts";
|
||||||
|
|
||||||
export type Adjustment = {
|
export interface Adjustment {
|
||||||
address: string
|
address: string;
|
||||||
amount: Amount
|
amount: Amount;
|
||||||
tag?: number
|
tag?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MaxAdjustment = {
|
export interface MaxAdjustment {
|
||||||
address: string
|
address: string;
|
||||||
maxAmount: Amount
|
maxAmount: Amount;
|
||||||
tag?: number
|
tag?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MinAdjustment = {
|
export interface MinAdjustment {
|
||||||
address: string
|
address: string;
|
||||||
minAmount: Amount
|
minAmount: Amount;
|
||||||
tag?: number
|
tag?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
export interface Amount extends Issue {
|
export interface Amount extends Issue {
|
||||||
value: string
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RippledAmount = string | Amount
|
export type RippledAmount = string | Amount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specification of which currency the account taking the offer would pay/
|
* Specification of which currency the account taking the offer would pay/
|
||||||
@@ -10,15 +10,15 @@ export type RippledAmount = string | Amount
|
|||||||
* Similar to currency amounts.
|
* Similar to currency amounts.
|
||||||
*/
|
*/
|
||||||
export interface TakerRequestAmount {
|
export interface TakerRequestAmount {
|
||||||
currency: string
|
currency: string;
|
||||||
issuer?: string
|
issuer?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A currency-counterparty pair, or just currency if it's XRP.
|
* A currency-counterparty pair, or just currency if it's XRP.
|
||||||
*/
|
*/
|
||||||
export interface Issue {
|
export interface Issue {
|
||||||
currency: string
|
currency: string;
|
||||||
issuer?: string
|
issuer?: string;
|
||||||
counterparty?: string
|
counterparty?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
export * from './adjustments'
|
export * from "./adjustments";
|
||||||
export * from './amounts'
|
export * from "./amounts";
|
||||||
export * from './ledger'
|
export * from "./ledger";
|
||||||
export * from './ledger_data'
|
export * from "./ledger_data";
|
||||||
export * from './ledger_entries'
|
export * from "./ledger_entries";
|
||||||
export * from './memos'
|
export * from "./memos";
|
||||||
export * from './orders'
|
export * from "./orders";
|
||||||
export * from './queue_data'
|
export * from "./queue_data";
|
||||||
export * from './settings'
|
export * from "./settings";
|
||||||
export * from './signers'
|
export * from "./signers";
|
||||||
export * from './transactions'
|
export * from "./transactions";
|
||||||
export * from './trustlines'
|
export * from "./trustlines";
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
export interface Ledger {
|
export interface Ledger {
|
||||||
account_hash: string
|
account_hash: string;
|
||||||
close_time: number
|
close_time: number;
|
||||||
close_time_human: string
|
close_time_human: string;
|
||||||
close_time_resolution: number
|
close_time_resolution: number;
|
||||||
closed: boolean
|
closed: boolean;
|
||||||
ledger_hash: string
|
ledger_hash: string;
|
||||||
ledger_index: string
|
ledger_index: string;
|
||||||
parent_hash: string
|
parent_hash: string;
|
||||||
total_coins: string
|
total_coins: string;
|
||||||
transaction_hash: string
|
transaction_hash: string;
|
||||||
transactions: string[] | object[]
|
transactions: string[] | object[];
|
||||||
close_flags?: number
|
close_flags?: number;
|
||||||
parent_close_time?: number
|
parent_close_time?: number;
|
||||||
accountState?: any[]
|
accountState?: any[];
|
||||||
validated?: boolean
|
validated?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://xrpl.org/subscribe.html#ledger-stream
|
// https://xrpl.org/subscribe.html#ledger-stream
|
||||||
export type LedgerClosedEvent = {
|
export interface LedgerClosedEvent {
|
||||||
type: 'ledgerClosed'
|
type: "ledgerClosed";
|
||||||
fee_base: number
|
fee_base: number;
|
||||||
fee_ref: number
|
fee_ref: number;
|
||||||
ledger_hash: string
|
ledger_hash: string;
|
||||||
ledger_index: number
|
ledger_index: number;
|
||||||
ledger_time: number
|
ledger_time: number;
|
||||||
reserve_base: number
|
reserve_base: number;
|
||||||
reserve_inc: number
|
reserve_inc: number;
|
||||||
txn_count: number
|
txn_count: number;
|
||||||
validated_ledgers: string
|
validated_ledgers: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
export interface LedgerData {
|
export interface LedgerData {
|
||||||
ledger_index: string
|
ledger_index: string;
|
||||||
ledger_hash: string
|
ledger_hash: string;
|
||||||
marker: string
|
marker: string;
|
||||||
state: ({data?: string; LedgerEntryType?: string; index: string} & any)[]
|
state: Array<
|
||||||
|
{ data?: string; LedgerEntryType?: string; index: string } & any
|
||||||
|
>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,175 +1,176 @@
|
|||||||
import {SignerEntry} from './index'
|
import { Amount, RippledAmount } from "./amounts";
|
||||||
import {Amount, RippledAmount} from './amounts'
|
|
||||||
|
import { SignerEntry } from "./index";
|
||||||
|
|
||||||
export interface AccountRootLedgerEntry {
|
export interface AccountRootLedgerEntry {
|
||||||
LedgerEntryType: 'AccountRoot'
|
LedgerEntryType: "AccountRoot";
|
||||||
Account: string
|
Account: string;
|
||||||
Balance: string
|
Balance: string;
|
||||||
Flags: number
|
Flags: number;
|
||||||
OwnerCount: number
|
OwnerCount: number;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
Sequence: number
|
Sequence: number;
|
||||||
AccountTxnID?: string
|
AccountTxnID?: string;
|
||||||
Domain?: string
|
Domain?: string;
|
||||||
EmailHash?: string
|
EmailHash?: string;
|
||||||
MessageKey?: string
|
MessageKey?: string;
|
||||||
RegularKey?: string
|
RegularKey?: string;
|
||||||
TickSize?: number
|
TickSize?: number;
|
||||||
TransferRate?: number
|
TransferRate?: number;
|
||||||
WalletLocator?: string
|
WalletLocator?: string;
|
||||||
WalletSize?: number // DEPRECATED
|
WalletSize?: number; // DEPRECATED
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AmendmentsLedgerEntry {
|
export interface AmendmentsLedgerEntry {
|
||||||
LedgerEntryType: 'Amendments'
|
LedgerEntryType: "Amendments";
|
||||||
Amendments?: string[]
|
Amendments?: string[];
|
||||||
Majorities?: any[]
|
Majorities?: any[];
|
||||||
Flags: 0
|
Flags: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CheckLedgerEntry {
|
export interface CheckLedgerEntry {
|
||||||
LedgerEntryType: 'Check'
|
LedgerEntryType: "Check";
|
||||||
Account: string
|
Account: string;
|
||||||
Destination
|
Destination;
|
||||||
string
|
string;
|
||||||
Flags: 0
|
Flags: 0;
|
||||||
OwnerNode: string
|
OwnerNode: string;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
SendMax: string | object
|
SendMax: string | object;
|
||||||
Sequence: number
|
Sequence: number;
|
||||||
DestinationNode: string
|
DestinationNode: string;
|
||||||
DestinationTag: number
|
DestinationTag: number;
|
||||||
Expiration: number
|
Expiration: number;
|
||||||
InvoiceID: string
|
InvoiceID: string;
|
||||||
SourceTag: number
|
SourceTag: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DepositPreauthLedgerEntry {
|
export interface DepositPreauthLedgerEntry {
|
||||||
LedgerEntryType: 'DepositPreauth'
|
LedgerEntryType: "DepositPreauth";
|
||||||
Account: string
|
Account: string;
|
||||||
Authorize: string
|
Authorize: string;
|
||||||
OwnerNode: string
|
OwnerNode: string;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DirectoryNodeLedgerEntry {
|
export interface DirectoryNodeLedgerEntry {
|
||||||
LedgerEntryType: 'DirectoryNode'
|
LedgerEntryType: "DirectoryNode";
|
||||||
Flags: number
|
Flags: number;
|
||||||
RootIndex: string
|
RootIndex: string;
|
||||||
Indexes: string[]
|
Indexes: string[];
|
||||||
IndexNext?: number
|
IndexNext?: number;
|
||||||
IndexPrevious?: number
|
IndexPrevious?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OfferDirectoryNodeLedgerEntry
|
export interface OfferDirectoryNodeLedgerEntry
|
||||||
extends DirectoryNodeLedgerEntry {
|
extends DirectoryNodeLedgerEntry {
|
||||||
TakerPaysCurrency: string
|
TakerPaysCurrency: string;
|
||||||
TakerPaysIssuer: string
|
TakerPaysIssuer: string;
|
||||||
TakerGetsCurrency: string
|
TakerGetsCurrency: string;
|
||||||
TakerGetsIssuer: string
|
TakerGetsIssuer: string;
|
||||||
ExchangeRate?: number // DEPRECATED
|
ExchangeRate?: number; // DEPRECATED
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OwnerDirectoryNodeLedgerEntry
|
export interface OwnerDirectoryNodeLedgerEntry
|
||||||
extends DirectoryNodeLedgerEntry {
|
extends DirectoryNodeLedgerEntry {
|
||||||
Owner: string
|
Owner: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EscrowLedgerEntry {
|
export interface EscrowLedgerEntry {
|
||||||
LedgerEntryType: 'Escrow'
|
LedgerEntryType: "Escrow";
|
||||||
Account: string
|
Account: string;
|
||||||
Destination: string
|
Destination: string;
|
||||||
Amount: string
|
Amount: string;
|
||||||
Condition?: string
|
Condition?: string;
|
||||||
CancelAfter?: number
|
CancelAfter?: number;
|
||||||
FinishAfter?: number
|
FinishAfter?: number;
|
||||||
Flags: number
|
Flags: number;
|
||||||
SourceTag?: number
|
SourceTag?: number;
|
||||||
DestinationTag?: number
|
DestinationTag?: number;
|
||||||
OwnerNode: string
|
OwnerNode: string;
|
||||||
DestinationNode?: string
|
DestinationNode?: string;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FeeSettingsLedgerEntry {
|
export interface FeeSettingsLedgerEntry {
|
||||||
LedgerEntryType: 'FeeSettings'
|
LedgerEntryType: "FeeSettings";
|
||||||
BaseFee: string
|
BaseFee: string;
|
||||||
ReferenceFeeUnits: number
|
ReferenceFeeUnits: number;
|
||||||
ReserveBase: number
|
ReserveBase: number;
|
||||||
ReserveIncrement: number
|
ReserveIncrement: number;
|
||||||
Flags: number
|
Flags: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LedgerHashesLedgerEntry {
|
export interface LedgerHashesLedgerEntry {
|
||||||
LedgerEntryType: 'LedgerHashes'
|
LedgerEntryType: "LedgerHashes";
|
||||||
Hashes: string[]
|
Hashes: string[];
|
||||||
Flags: number
|
Flags: number;
|
||||||
FirstLedgerSequence?: number // DEPRECATED
|
FirstLedgerSequence?: number; // DEPRECATED
|
||||||
LastLedgerSequence?: number
|
LastLedgerSequence?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OfferLedgerEntry {
|
export interface OfferLedgerEntry {
|
||||||
LedgerEntryType: 'Offer'
|
LedgerEntryType: "Offer";
|
||||||
Flags: number
|
Flags: number;
|
||||||
Account: string
|
Account: string;
|
||||||
Sequence: number
|
Sequence: number;
|
||||||
TakerPays: RippledAmount
|
TakerPays: RippledAmount;
|
||||||
TakerGets: RippledAmount
|
TakerGets: RippledAmount;
|
||||||
BookDirectory: string
|
BookDirectory: string;
|
||||||
BookNode: string
|
BookNode: string;
|
||||||
OwnerNode: string
|
OwnerNode: string;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
Expiration?: number
|
Expiration?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PayChannelLedgerEntry {
|
export interface PayChannelLedgerEntry {
|
||||||
LedgerEntryType: 'PayChannel'
|
LedgerEntryType: "PayChannel";
|
||||||
Sequence: number
|
Sequence: number;
|
||||||
Account: string
|
Account: string;
|
||||||
Amount: string
|
Amount: string;
|
||||||
Balance: string
|
Balance: string;
|
||||||
PublicKey: string
|
PublicKey: string;
|
||||||
Destination: string
|
Destination: string;
|
||||||
SettleDelay: number
|
SettleDelay: number;
|
||||||
Expiration?: number
|
Expiration?: number;
|
||||||
CancelAfter?: number
|
CancelAfter?: number;
|
||||||
SourceTag?: number
|
SourceTag?: number;
|
||||||
DestinationTag?: number
|
DestinationTag?: number;
|
||||||
OwnerNode: string
|
OwnerNode: string;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
index: string
|
index: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RippleStateLedgerEntry {
|
export interface RippleStateLedgerEntry {
|
||||||
LedgerEntryType: 'RippleState'
|
LedgerEntryType: "RippleState";
|
||||||
Flags: number
|
Flags: number;
|
||||||
Balance: Amount
|
Balance: Amount;
|
||||||
LowLimit: Amount
|
LowLimit: Amount;
|
||||||
HighLimit: Amount
|
HighLimit: Amount;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
LowNode?: string
|
LowNode?: string;
|
||||||
HighNode?: string
|
HighNode?: string;
|
||||||
LowQualityIn?: number
|
LowQualityIn?: number;
|
||||||
LowQualityOut?: number
|
LowQualityOut?: number;
|
||||||
HighQualityIn?: number
|
HighQualityIn?: number;
|
||||||
HighQualityOut?: number
|
HighQualityOut?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SignerListLedgerEntry {
|
export interface SignerListLedgerEntry {
|
||||||
LedgerEntryType: 'SignerList'
|
LedgerEntryType: "SignerList";
|
||||||
OwnerNode: string
|
OwnerNode: string;
|
||||||
SignerQuorum: number
|
SignerQuorum: number;
|
||||||
SignerEntries: SignerEntry[]
|
SignerEntries: SignerEntry[];
|
||||||
SignerListID: number
|
SignerListID: number;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// see https://ripple.com/build/ledger-format/#ledger-object-types
|
// see https://ripple.com/build/ledger-format/#ledger-object-types
|
||||||
@@ -187,4 +188,4 @@ export type LedgerEntry =
|
|||||||
| OfferLedgerEntry
|
| OfferLedgerEntry
|
||||||
| PayChannelLedgerEntry
|
| PayChannelLedgerEntry
|
||||||
| RippleStateLedgerEntry
|
| RippleStateLedgerEntry
|
||||||
| SignerListLedgerEntry
|
| SignerListLedgerEntry;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export type Memo = {
|
export interface Memo {
|
||||||
type?: string
|
type?: string;
|
||||||
format?: string
|
format?: string;
|
||||||
data?: string
|
data?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import {Amount} from './amounts'
|
import { Amount } from "./amounts";
|
||||||
import {Memo} from './memos'
|
import { Memo } from "./memos";
|
||||||
|
|
||||||
export type FormattedOrderSpecification = {
|
export interface FormattedOrderSpecification {
|
||||||
direction: string
|
direction: string;
|
||||||
quantity: Amount
|
quantity: Amount;
|
||||||
totalPrice: Amount
|
totalPrice: Amount;
|
||||||
immediateOrCancel?: boolean
|
immediateOrCancel?: boolean;
|
||||||
fillOrKill?: boolean
|
fillOrKill?: boolean;
|
||||||
expirationTime?: string
|
expirationTime?: string;
|
||||||
orderToReplace?: number
|
orderToReplace?: number;
|
||||||
memos?: Memo[]
|
memos?: Memo[];
|
||||||
// If enabled, the offer will not consume offers that exactly match it, and
|
// If enabled, the offer will not consume offers that exactly match it, and
|
||||||
// instead becomes an Offer node in the ledger. It will still consume offers
|
// instead becomes an Offer node in the ledger. It will still consume offers
|
||||||
// that cross it.
|
// that cross it.
|
||||||
passive?: boolean
|
passive?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
export interface QueueTransaction {
|
export interface QueueTransaction {
|
||||||
auth_change: boolean
|
auth_change: boolean;
|
||||||
fee: string
|
fee: string;
|
||||||
fee_level: string
|
fee_level: string;
|
||||||
max_spend_drops: string
|
max_spend_drops: string;
|
||||||
seq: number
|
seq: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QueueData {
|
export interface QueueData {
|
||||||
txn_count: number
|
txn_count: number;
|
||||||
auth_change_queued?: boolean
|
auth_change_queued?: boolean;
|
||||||
lowest_sequence?: number
|
lowest_sequence?: number;
|
||||||
highest_sequence?: number
|
highest_sequence?: number;
|
||||||
max_spend_drops_total?: string
|
max_spend_drops_total?: string;
|
||||||
transactions?: QueueTransaction[]
|
transactions?: QueueTransaction[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
import {Memo} from './memos'
|
import { Memo } from "./memos";
|
||||||
|
|
||||||
export type WeightedSigner = {
|
export interface WeightedSigner {
|
||||||
address: string
|
address: string;
|
||||||
weight: number
|
weight: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Signers = {
|
export interface Signers {
|
||||||
threshold?: number
|
threshold?: number;
|
||||||
weights: WeightedSigner[]
|
weights: WeightedSigner[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormattedSettings = {
|
export interface FormattedSettings {
|
||||||
defaultRipple?: boolean
|
defaultRipple?: boolean;
|
||||||
depositAuth?: boolean
|
depositAuth?: boolean;
|
||||||
disableMasterKey?: boolean
|
disableMasterKey?: boolean;
|
||||||
disallowIncomingXRP?: boolean
|
disallowIncomingXRP?: boolean;
|
||||||
domain?: string
|
domain?: string;
|
||||||
emailHash?: string | null
|
emailHash?: string | null;
|
||||||
walletLocator?: string | null
|
walletLocator?: string | null;
|
||||||
enableTransactionIDTracking?: boolean
|
enableTransactionIDTracking?: boolean;
|
||||||
globalFreeze?: boolean
|
globalFreeze?: boolean;
|
||||||
memos?: Memo[]
|
memos?: Memo[];
|
||||||
messageKey?: string
|
messageKey?: string;
|
||||||
noFreeze?: boolean
|
noFreeze?: boolean;
|
||||||
passwordSpent?: boolean
|
passwordSpent?: boolean;
|
||||||
regularKey?: string
|
regularKey?: string;
|
||||||
requireAuthorization?: boolean
|
requireAuthorization?: boolean;
|
||||||
requireDestinationTag?: boolean
|
requireDestinationTag?: boolean;
|
||||||
signers?: Signers
|
signers?: Signers;
|
||||||
transferRate?: number | null
|
transferRate?: number | null;
|
||||||
tickSize?: number
|
tickSize?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export interface SignerEntry {
|
export interface SignerEntry {
|
||||||
SignerEntry: {
|
SignerEntry: {
|
||||||
Account: string
|
Account: string;
|
||||||
SignerWeight: number
|
SignerWeight: number;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
import {RippledAmount} from './amounts'
|
import { RippledAmount } from "./amounts";
|
||||||
import {Memo} from './memos'
|
import { Memo } from "./memos";
|
||||||
|
|
||||||
export interface OfferCreateTransaction {
|
export interface OfferCreateTransaction {
|
||||||
TransactionType: 'OfferCreate'
|
TransactionType: "OfferCreate";
|
||||||
Account: string
|
Account: string;
|
||||||
AccountTxnID?: string
|
AccountTxnID?: string;
|
||||||
Fee: string
|
Fee: string;
|
||||||
Field: any
|
Field: any;
|
||||||
Flags: number
|
Flags: number;
|
||||||
LastLedgerSequence?: number
|
LastLedgerSequence?: number;
|
||||||
Sequence: number
|
Sequence: number;
|
||||||
Signers: any[]
|
Signers: any[];
|
||||||
SigningPubKey: string
|
SigningPubKey: string;
|
||||||
SourceTag?: number
|
SourceTag?: number;
|
||||||
TakerGets: RippledAmount
|
TakerGets: RippledAmount;
|
||||||
TakerPays: RippledAmount
|
TakerPays: RippledAmount;
|
||||||
TxnSignature: string
|
TxnSignature: string;
|
||||||
Expiration?: number
|
Expiration?: number;
|
||||||
Memos?: Memo[]
|
Memos?: Memo[];
|
||||||
OfferSequence?: number
|
OfferSequence?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SignedTransaction {
|
export interface SignedTransaction {
|
||||||
signedTransaction: string
|
signedTransaction: string;
|
||||||
id: string
|
id: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
import {Memo} from './memos'
|
import { Memo } from "./memos";
|
||||||
|
|
||||||
export interface Trustline {
|
export interface Trustline {
|
||||||
account: string
|
account: string;
|
||||||
balance: string
|
balance: string;
|
||||||
currency: string
|
currency: string;
|
||||||
limit: string
|
limit: string;
|
||||||
limit_peer: string
|
limit_peer: string;
|
||||||
quality_in: number
|
quality_in: number;
|
||||||
quality_out: number
|
quality_out: number;
|
||||||
no_ripple?: boolean
|
no_ripple?: boolean;
|
||||||
no_ripple_peer?: boolean
|
no_ripple_peer?: boolean;
|
||||||
freeze?: boolean
|
freeze?: boolean;
|
||||||
freeze_peer?: boolean
|
freeze_peer?: boolean;
|
||||||
authorized?: boolean
|
authorized?: boolean;
|
||||||
peer_authorized?: boolean
|
peer_authorized?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormattedTrustlineSpecification = {
|
export interface FormattedTrustlineSpecification {
|
||||||
currency: string
|
currency: string;
|
||||||
counterparty: string
|
counterparty: string;
|
||||||
limit: string
|
limit: string;
|
||||||
qualityIn?: number
|
qualityIn?: number;
|
||||||
qualityOut?: number
|
qualityOut?: number;
|
||||||
ripplingDisabled?: boolean
|
ripplingDisabled?: boolean;
|
||||||
authorized?: boolean
|
authorized?: boolean;
|
||||||
frozen?: boolean
|
frozen?: boolean;
|
||||||
memos?: Memo[]
|
memos?: Memo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormattedTrustline = {
|
export interface FormattedTrustline {
|
||||||
specification: FormattedTrustlineSpecification
|
specification: FormattedTrustlineSpecification;
|
||||||
counterparty: {
|
counterparty: {
|
||||||
limit: string
|
limit: string;
|
||||||
ripplingDisabled?: boolean
|
ripplingDisabled?: boolean;
|
||||||
frozen?: boolean
|
frozen?: boolean;
|
||||||
authorized?: boolean
|
authorized?: boolean;
|
||||||
}
|
};
|
||||||
state: {
|
state: {
|
||||||
balance: string
|
balance: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import _ from 'lodash'
|
import _ from "lodash";
|
||||||
import {ValidationError} from './errors'
|
|
||||||
import {schemaValidate} from './schema-validator'
|
import { ValidationError } from "./errors";
|
||||||
|
import { schemaValidate } from "./schema-validator";
|
||||||
|
|
||||||
function error(text) {
|
function error(text) {
|
||||||
return new ValidationError(text)
|
return new ValidationError(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateLedgerRange(options) {
|
function validateLedgerRange(options) {
|
||||||
@@ -13,158 +14,161 @@ function validateLedgerRange(options) {
|
|||||||
options.maxLedgerVersion != null
|
options.maxLedgerVersion != null
|
||||||
) {
|
) {
|
||||||
if (Number(options.minLedgerVersion) > Number(options.maxLedgerVersion)) {
|
if (Number(options.minLedgerVersion) > Number(options.maxLedgerVersion)) {
|
||||||
throw error('minLedgerVersion must not be greater than maxLedgerVersion')
|
throw error("minLedgerVersion must not be greater than maxLedgerVersion");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateOptions(schema, instance) {
|
function validateOptions(schema, instance) {
|
||||||
schemaValidate(schema, instance)
|
schemaValidate(schema, instance);
|
||||||
validateLedgerRange(instance.options)
|
validateLedgerRange(instance.options);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getPaths = _.partial(schemaValidate, 'getPathsParameters')
|
export const getPaths = _.partial(schemaValidate, "getPathsParameters");
|
||||||
|
|
||||||
export const getTransactions = _.partial(
|
export const getTransactions = _.partial(
|
||||||
validateOptions,
|
validateOptions,
|
||||||
'getTransactionsParameters'
|
"getTransactionsParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const getSettings = _.partial(validateOptions, 'getSettingsParameters')
|
export const getSettings = _.partial(validateOptions, "getSettingsParameters");
|
||||||
|
|
||||||
export const getAccountInfo = _.partial(
|
export const getAccountInfo = _.partial(
|
||||||
validateOptions,
|
validateOptions,
|
||||||
'getAccountInfoParameters'
|
"getAccountInfoParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const getTrustlines = _.partial(
|
export const getTrustlines = _.partial(
|
||||||
validateOptions,
|
validateOptions,
|
||||||
'getTrustlinesParameters'
|
"getTrustlinesParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const getBalances = _.partial(validateOptions, 'getBalancesParameters')
|
export const getBalances = _.partial(validateOptions, "getBalancesParameters");
|
||||||
|
|
||||||
export const getBalanceSheet = _.partial(
|
export const getBalanceSheet = _.partial(
|
||||||
validateOptions,
|
validateOptions,
|
||||||
'getBalanceSheetParameters'
|
"getBalanceSheetParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const getOrders = _.partial(validateOptions, 'getOrdersParameters')
|
export const getOrders = _.partial(validateOptions, "getOrdersParameters");
|
||||||
|
|
||||||
export const getOrderbook = _.partial(validateOptions, 'getOrderbookParameters')
|
export const getOrderbook = _.partial(
|
||||||
|
validateOptions,
|
||||||
|
"getOrderbookParameters"
|
||||||
|
);
|
||||||
|
|
||||||
export const getTransaction = _.partial(
|
export const getTransaction = _.partial(
|
||||||
validateOptions,
|
validateOptions,
|
||||||
'getTransactionParameters'
|
"getTransactionParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const getPaymentChannel = _.partial(
|
export const getPaymentChannel = _.partial(
|
||||||
validateOptions,
|
validateOptions,
|
||||||
'getPaymentChannelParameters'
|
"getPaymentChannelParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const getLedger = _.partial(validateOptions, 'getLedgerParameters')
|
export const getLedger = _.partial(validateOptions, "getLedgerParameters");
|
||||||
|
|
||||||
export const preparePayment = _.partial(
|
export const preparePayment = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'preparePaymentParameters'
|
"preparePaymentParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const prepareOrder = _.partial(schemaValidate, 'prepareOrderParameters')
|
export const prepareOrder = _.partial(schemaValidate, "prepareOrderParameters");
|
||||||
|
|
||||||
export const prepareOrderCancellation = _.partial(
|
export const prepareOrderCancellation = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'prepareOrderCancellationParameters'
|
"prepareOrderCancellationParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const prepareTrustline = _.partial(
|
export const prepareTrustline = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'prepareTrustlineParameters'
|
"prepareTrustlineParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const prepareSettings = _.partial(
|
export const prepareSettings = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'prepareSettingsParameters'
|
"prepareSettingsParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const prepareEscrowCreation = _.partial(
|
export const prepareEscrowCreation = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'prepareEscrowCreationParameters'
|
"prepareEscrowCreationParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const prepareEscrowCancellation = _.partial(
|
export const prepareEscrowCancellation = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'prepareEscrowCancellationParameters'
|
"prepareEscrowCancellationParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const prepareEscrowExecution = _.partial(
|
export const prepareEscrowExecution = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'prepareEscrowExecutionParameters'
|
"prepareEscrowExecutionParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const preparePaymentChannelCreate = _.partial(
|
export const preparePaymentChannelCreate = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'preparePaymentChannelCreateParameters'
|
"preparePaymentChannelCreateParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const preparePaymentChannelFund = _.partial(
|
export const preparePaymentChannelFund = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'preparePaymentChannelFundParameters'
|
"preparePaymentChannelFundParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const preparePaymentChannelClaim = _.partial(
|
export const preparePaymentChannelClaim = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'preparePaymentChannelClaimParameters'
|
"preparePaymentChannelClaimParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const prepareCheckCreate = _.partial(
|
export const prepareCheckCreate = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'prepareCheckCreateParameters'
|
"prepareCheckCreateParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const prepareCheckCash = _.partial(
|
export const prepareCheckCash = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'prepareCheckCashParameters'
|
"prepareCheckCashParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const prepareCheckCancel = _.partial(
|
export const prepareCheckCancel = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'prepareCheckCancelParameters'
|
"prepareCheckCancelParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const prepareTicketCreate = _.partial(
|
export const prepareTicketCreate = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'prepareTicketParameters'
|
"prepareTicketParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const sign = _.partial(schemaValidate, 'signParameters')
|
export const sign = _.partial(schemaValidate, "signParameters");
|
||||||
|
|
||||||
export const combine = _.partial(schemaValidate, 'combineParameters')
|
export const combine = _.partial(schemaValidate, "combineParameters");
|
||||||
|
|
||||||
export const submit = _.partial(schemaValidate, 'submitParameters')
|
export const submit = _.partial(schemaValidate, "submitParameters");
|
||||||
|
|
||||||
export const computeLedgerHash = _.partial(
|
export const computeLedgerHash = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'computeLedgerHashParameters'
|
"computeLedgerHashParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const generateAddress = _.partial(
|
export const generateAddress = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'generateAddressParameters'
|
"generateAddressParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const signPaymentChannelClaim = _.partial(
|
export const signPaymentChannelClaim = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'signPaymentChannelClaimParameters'
|
"signPaymentChannelClaimParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const verifyPaymentChannelClaim = _.partial(
|
export const verifyPaymentChannelClaim = _.partial(
|
||||||
schemaValidate,
|
schemaValidate,
|
||||||
'verifyPaymentChannelClaimParameters'
|
"verifyPaymentChannelClaimParameters"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const apiOptions = _.partial(schemaValidate, 'api-options')
|
export const apiOptions = _.partial(schemaValidate, "api-options");
|
||||||
|
|
||||||
export const instructions = _.partial(schemaValidate, 'instructions')
|
export const instructions = _.partial(schemaValidate, "instructions");
|
||||||
|
|
||||||
export const tx_json = _.partial(schemaValidate, 'tx-json')
|
export const tx_json = _.partial(schemaValidate, "tx-json");
|
||||||
|
|||||||
14
src/index.ts
14
src/index.ts
@@ -1,14 +1,14 @@
|
|||||||
export {Client} from './client'
|
export { Client } from "./client";
|
||||||
|
|
||||||
export * from './transaction/types'
|
export * from "./transaction/types";
|
||||||
|
|
||||||
export * from './common/types/objects/ledger'
|
export * from "./common/types/objects/ledger";
|
||||||
|
|
||||||
export * from './models/methods'
|
export * from "./models/methods";
|
||||||
|
|
||||||
export * from './utils'
|
export * from "./utils";
|
||||||
|
|
||||||
// Broadcast client is experimental
|
// Broadcast client is experimental
|
||||||
export {BroadcastClient} from './client/broadcastClient'
|
export { BroadcastClient } from "./client/broadcastClient";
|
||||||
|
|
||||||
export * from './Wallet'
|
export * from "./Wallet";
|
||||||
|
|||||||
@@ -1,42 +1,46 @@
|
|||||||
import * as utils from './utils'
|
import { Client } from "..";
|
||||||
import {validate, ensureClassicAddress} from '../common'
|
import { Connection } from "../client";
|
||||||
import {Connection} from '../client'
|
import { validate, ensureClassicAddress } from "../common";
|
||||||
import {GetTrustlinesOptions} from './trustlines'
|
import { FormattedTrustline } from "../common/types/objects/trustlines";
|
||||||
import {FormattedTrustline} from '../common/types/objects/trustlines'
|
|
||||||
import {Client} from '..'
|
|
||||||
|
|
||||||
export type Balance = {
|
import { GetTrustlinesOptions } from "./trustlines";
|
||||||
value: string
|
import * as utils from "./utils";
|
||||||
currency: string
|
|
||||||
counterparty?: string
|
export interface Balance {
|
||||||
|
value: string;
|
||||||
|
currency: string;
|
||||||
|
counterparty?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetBalances = Array<Balance>
|
export type GetBalances = Balance[];
|
||||||
|
|
||||||
function getTrustlineBalanceAmount(trustline: FormattedTrustline): Balance {
|
function getTrustlineBalanceAmount(trustline: FormattedTrustline): Balance {
|
||||||
return {
|
return {
|
||||||
currency: trustline.specification.currency,
|
currency: trustline.specification.currency,
|
||||||
counterparty: trustline.specification.counterparty,
|
counterparty: trustline.specification.counterparty,
|
||||||
value: trustline.state.balance
|
value: trustline.state.balance,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatBalances(options: GetTrustlinesOptions, balances: {xrp: string, trustlines: FormattedTrustline[]}) {
|
function formatBalances(
|
||||||
const result = balances.trustlines.map(getTrustlineBalanceAmount)
|
options: GetTrustlinesOptions,
|
||||||
|
balances: { xrp: string; trustlines: FormattedTrustline[] }
|
||||||
|
) {
|
||||||
|
const result = balances.trustlines.map(getTrustlineBalanceAmount);
|
||||||
if (
|
if (
|
||||||
!(options.counterparty || (options.currency && options.currency !== 'XRP'))
|
!(options.counterparty || (options.currency && options.currency !== "XRP"))
|
||||||
) {
|
) {
|
||||||
const xrpBalance = {
|
const xrpBalance = {
|
||||||
currency: 'XRP',
|
currency: "XRP",
|
||||||
value: balances.xrp
|
value: balances.xrp,
|
||||||
}
|
};
|
||||||
result.unshift(xrpBalance)
|
result.unshift(xrpBalance);
|
||||||
}
|
}
|
||||||
if (options.limit && result.length > options.limit) {
|
if (options.limit && result.length > options.limit) {
|
||||||
const toRemove = result.length - options.limit
|
const toRemove = result.length - options.limit;
|
||||||
result.splice(-toRemove, toRemove)
|
result.splice(-toRemove, toRemove);
|
||||||
}
|
}
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLedgerVersionHelper(
|
function getLedgerVersionHelper(
|
||||||
@@ -44,12 +48,14 @@ function getLedgerVersionHelper(
|
|||||||
optionValue?: number
|
optionValue?: number
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
if (optionValue != null && optionValue !== null) {
|
if (optionValue != null && optionValue !== null) {
|
||||||
return Promise.resolve(optionValue)
|
return Promise.resolve(optionValue);
|
||||||
}
|
}
|
||||||
return connection.request({
|
return connection
|
||||||
command: 'ledger',
|
.request({
|
||||||
ledger_index: 'validated'
|
command: "ledger",
|
||||||
}).then(response => response.result.ledger_index);
|
ledger_index: "validated",
|
||||||
|
})
|
||||||
|
.then((response) => response.result.ledger_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBalances(
|
function getBalances(
|
||||||
@@ -57,26 +63,23 @@ function getBalances(
|
|||||||
address: string,
|
address: string,
|
||||||
options: GetTrustlinesOptions = {}
|
options: GetTrustlinesOptions = {}
|
||||||
): Promise<GetBalances> {
|
): Promise<GetBalances> {
|
||||||
validate.getTrustlines({address, options})
|
validate.getTrustlines({ address, options });
|
||||||
|
|
||||||
// Only support retrieving balances without a tag,
|
// Only support retrieving balances without a tag,
|
||||||
// since we currently do not calculate balances
|
// since we currently do not calculate balances
|
||||||
// on a per-tag basis. Apps must interpret and
|
// on a per-tag basis. Apps must interpret and
|
||||||
// use tags independent of the XRP Ledger, comparing
|
// use tags independent of the XRP Ledger, comparing
|
||||||
// with the XRP Ledger's balance as an accounting check.
|
// with the XRP Ledger's balance as an accounting check.
|
||||||
address = ensureClassicAddress(address)
|
address = ensureClassicAddress(address);
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
getLedgerVersionHelper(
|
getLedgerVersionHelper(this.connection, options.ledgerVersion).then(
|
||||||
this.connection,
|
(ledgerVersion) => utils.getXRPBalance(this, address, ledgerVersion)
|
||||||
options.ledgerVersion
|
|
||||||
).then((ledgerVersion) =>
|
|
||||||
utils.getXRPBalance(this, address, ledgerVersion)
|
|
||||||
),
|
),
|
||||||
this.getTrustlines(address, options)
|
this.getTrustlines(address, options),
|
||||||
]).then((results) =>
|
]).then((results) =>
|
||||||
formatBalances(options, {xrp: results[0], trustlines: results[1]})
|
formatBalances(options, { xrp: results[0], trustlines: results[1] })
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default getBalances
|
export default getBalances;
|
||||||
|
|||||||
@@ -1,45 +1,46 @@
|
|||||||
import _ from 'lodash'
|
import BigNumber from "bignumber.js";
|
||||||
import * as utils from './utils'
|
import _ from "lodash";
|
||||||
|
|
||||||
|
import type { Client } from "../client";
|
||||||
|
import type { BookOffer } from "../common/types/commands";
|
||||||
|
import type { Issue } from "../common/types/objects";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
parseOrderbookOrder,
|
parseOrderbookOrder,
|
||||||
FormattedOrderbookOrder
|
FormattedOrderbookOrder,
|
||||||
} from './parse/orderbook-order'
|
} from "./parse/orderbook-order";
|
||||||
import {validate} from '../common'
|
import * as utils from "./utils";
|
||||||
import {Issue} from '../common/types/objects'
|
|
||||||
import {BookOffer} from '../common/types/commands'
|
|
||||||
import {Client} from '..'
|
|
||||||
import BigNumber from 'bignumber.js'
|
|
||||||
|
|
||||||
export type FormattedOrderbook = {
|
export interface FormattedOrderbook {
|
||||||
bids: FormattedOrderbookOrder[]
|
bids: FormattedOrderbookOrder[];
|
||||||
asks: FormattedOrderbookOrder[]
|
asks: FormattedOrderbookOrder[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSameIssue(a: Issue, b: Issue) {
|
function isSameIssue(a: Issue, b: Issue) {
|
||||||
return a.currency === b.currency && a.counterparty === b.counterparty
|
return a.currency === b.currency && a.counterparty === b.counterparty;
|
||||||
}
|
}
|
||||||
|
|
||||||
function directionFilter(direction: string, order: FormattedOrderbookOrder) {
|
function directionFilter(direction: string, order: FormattedOrderbookOrder) {
|
||||||
return order.specification.direction === direction
|
return order.specification.direction === direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
function flipOrder(order: FormattedOrderbookOrder) {
|
function flipOrder(order: FormattedOrderbookOrder) {
|
||||||
const specification = order.specification
|
const specification = order.specification;
|
||||||
const flippedSpecification = {
|
const flippedSpecification = {
|
||||||
quantity: specification.totalPrice,
|
quantity: specification.totalPrice,
|
||||||
totalPrice: specification.quantity,
|
totalPrice: specification.quantity,
|
||||||
direction: specification.direction === 'buy' ? 'sell' : 'buy'
|
direction: specification.direction === "buy" ? "sell" : "buy",
|
||||||
}
|
};
|
||||||
const newSpecification = _.merge({}, specification, flippedSpecification)
|
const newSpecification = _.merge({}, specification, flippedSpecification);
|
||||||
return _.merge({}, order, {specification: newSpecification})
|
return _.merge({}, order, { specification: newSpecification });
|
||||||
}
|
}
|
||||||
|
|
||||||
function alignOrder(
|
function alignOrder(
|
||||||
base: Issue,
|
base: Issue,
|
||||||
order: FormattedOrderbookOrder
|
order: FormattedOrderbookOrder
|
||||||
): FormattedOrderbookOrder {
|
): FormattedOrderbookOrder {
|
||||||
const quantity = order.specification.quantity
|
const quantity = order.specification.quantity;
|
||||||
return isSameIssue(quantity, base) ? order : flipOrder(order)
|
return isSameIssue(quantity, base) ? order : flipOrder(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatBidsAndAsks(
|
export function formatBidsAndAsks(
|
||||||
@@ -58,14 +59,17 @@ export function formatBidsAndAsks(
|
|||||||
// we sort the orders so that earlier orders are closer to mid-market
|
// we sort the orders so that earlier orders are closer to mid-market
|
||||||
const orders = offers
|
const orders = offers
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
return new BigNumber(a.quality).comparedTo(b.quality)
|
const qualityA = a.quality ?? 0;
|
||||||
})
|
const qualityB = b.quality ?? 0;
|
||||||
.map(parseOrderbookOrder)
|
|
||||||
|
|
||||||
const alignedOrders = orders.map(_.partial(alignOrder, orderbook.base))
|
return new BigNumber(qualityA).comparedTo(qualityB);
|
||||||
const bids = alignedOrders.filter(_.partial(directionFilter, 'buy'))
|
})
|
||||||
const asks = alignedOrders.filter(_.partial(directionFilter, 'sell'))
|
.map(parseOrderbookOrder);
|
||||||
return {bids, asks}
|
|
||||||
|
const alignedOrders = orders.map(_.partial(alignOrder, orderbook.base));
|
||||||
|
const bids = alignedOrders.filter(_.partial(directionFilter, "buy"));
|
||||||
|
const asks = alignedOrders.filter(_.partial(directionFilter, "sell"));
|
||||||
|
return { bids, asks };
|
||||||
}
|
}
|
||||||
|
|
||||||
// account is to specify a "perspective", which affects which unfunded offers
|
// account is to specify a "perspective", which affects which unfunded offers
|
||||||
@@ -79,25 +83,26 @@ async function makeRequest(
|
|||||||
) {
|
) {
|
||||||
const orderData = utils.renameCounterpartyToIssuerInOrder({
|
const orderData = utils.renameCounterpartyToIssuerInOrder({
|
||||||
taker_gets: takerGets,
|
taker_gets: takerGets,
|
||||||
taker_pays: takerPays
|
taker_pays: takerPays,
|
||||||
})
|
});
|
||||||
return client.requestAll({command: 'book_offers',
|
return client.requestAll({
|
||||||
|
command: "book_offers",
|
||||||
taker_gets: orderData.taker_gets,
|
taker_gets: orderData.taker_gets,
|
||||||
taker_pays: orderData.taker_pays,
|
taker_pays: orderData.taker_pays,
|
||||||
ledger_index: options.ledgerVersion || 'validated',
|
ledger_index: options.ledgerVersion || "validated",
|
||||||
limit: options.limit,
|
limit: options.limit,
|
||||||
taker
|
taker,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetOrderbookOptions = {
|
export interface GetOrderbookOptions {
|
||||||
limit?: number
|
limit?: number;
|
||||||
ledgerVersion?: number
|
ledgerVersion?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OrderbookInfo = {
|
export interface OrderbookInfo {
|
||||||
base: Issue
|
base: Issue;
|
||||||
counter: Issue
|
counter: Issue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getOrderbook(
|
export async function getOrderbook(
|
||||||
@@ -106,21 +111,19 @@ export async function getOrderbook(
|
|||||||
orderbook: OrderbookInfo,
|
orderbook: OrderbookInfo,
|
||||||
options: GetOrderbookOptions = {}
|
options: GetOrderbookOptions = {}
|
||||||
): Promise<FormattedOrderbook> {
|
): Promise<FormattedOrderbook> {
|
||||||
// 1. Validate
|
|
||||||
validate.getOrderbook({address, orderbook, options})
|
|
||||||
// 2. Make Request
|
// 2. Make Request
|
||||||
const [directOfferResults, reverseOfferResults] = await Promise.all([
|
const [directOfferResults, reverseOfferResults] = await Promise.all([
|
||||||
makeRequest(this, address, options, orderbook.base, orderbook.counter),
|
makeRequest(this, address, options, orderbook.base, orderbook.counter),
|
||||||
makeRequest(this, address, options, orderbook.counter, orderbook.base)
|
makeRequest(this, address, options, orderbook.counter, orderbook.base),
|
||||||
])
|
]);
|
||||||
// 3. Return Formatted Response
|
// 3. Return Formatted Response
|
||||||
const directOffers = _.flatMap(
|
const directOffers = _.flatMap(
|
||||||
directOfferResults,
|
directOfferResults,
|
||||||
(directOfferResult) => directOfferResult.result.offers
|
(directOfferResult) => directOfferResult.result.offers
|
||||||
)
|
);
|
||||||
const reverseOffers = _.flatMap(
|
const reverseOffers = _.flatMap(
|
||||||
reverseOfferResults,
|
reverseOfferResults,
|
||||||
(reverseOfferResult) => reverseOfferResult.result.offers
|
(reverseOfferResult) => reverseOfferResult.result.offers
|
||||||
)
|
);
|
||||||
return formatBidsAndAsks(orderbook, [...directOffers, ...reverseOffers])
|
return formatBidsAndAsks(orderbook, [...directOffers, ...reverseOffers]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,28 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
import {classicAddressToXAddress} from 'ripple-address-codec'
|
|
||||||
import {parseMemos} from './utils'
|
|
||||||
|
|
||||||
export type FormattedAccountDelete = {
|
import { classicAddressToXAddress } from "ripple-address-codec";
|
||||||
|
|
||||||
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import { parseMemos } from "./utils";
|
||||||
|
|
||||||
|
export interface FormattedAccountDelete {
|
||||||
// account (address) of an account to receive any leftover XRP after deleting the sending account.
|
// account (address) of an account to receive any leftover XRP after deleting the sending account.
|
||||||
// Must be a funded account in the ledger, and must not be the sending account.
|
// Must be a funded account in the ledger, and must not be the sending account.
|
||||||
destination: string
|
destination: string;
|
||||||
|
|
||||||
// (Optional) Arbitrary destination tag that identifies a hosted recipient or other information
|
// (Optional) Arbitrary destination tag that identifies a hosted recipient or other information
|
||||||
// for the recipient of the deleted account's leftover XRP. NB: Ensure that the hosted recipient is
|
// for the recipient of the deleted account's leftover XRP. NB: Ensure that the hosted recipient is
|
||||||
// able to account for AccountDelete transactions; if not, your balance may not be properly credited.
|
// able to account for AccountDelete transactions; if not, your balance may not be properly credited.
|
||||||
destinationTag?: number
|
destinationTag?: number;
|
||||||
|
|
||||||
// X-address of an account to receive any leftover XRP after deleting the sending account.
|
// X-address of an account to receive any leftover XRP after deleting the sending account.
|
||||||
// Must be a funded account in the ledger, and must not be the sending account.
|
// Must be a funded account in the ledger, and must not be the sending account.
|
||||||
destinationXAddress: string
|
destinationXAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseAccountDelete(tx: any): FormattedAccountDelete {
|
function parseAccountDelete(tx: any): FormattedAccountDelete {
|
||||||
assert.ok(tx.TransactionType === 'AccountDelete')
|
assert.ok(tx.TransactionType === "AccountDelete");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
@@ -29,8 +32,8 @@ function parseAccountDelete(tx: any): FormattedAccountDelete {
|
|||||||
tx.Destination,
|
tx.Destination,
|
||||||
tx.DestinationTag == null ? false : tx.DestinationTag,
|
tx.DestinationTag == null ? false : tx.DestinationTag,
|
||||||
false
|
false
|
||||||
)
|
),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseAccountDelete
|
export default parseAccountDelete;
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from "bignumber.js";
|
||||||
import parseAmount from './amount'
|
|
||||||
import {parseTimestamp, adjustQualityForXRP} from './utils'
|
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
import {orderFlags} from './flags'
|
|
||||||
import {FormattedOrderSpecification} from '../../common/types/objects'
|
|
||||||
|
|
||||||
export type FormattedAccountOrder = {
|
import { FormattedOrderSpecification } from "../../common/types/objects";
|
||||||
specification: FormattedOrderSpecification
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import parseAmount from "./amount";
|
||||||
|
import { orderFlags } from "./flags";
|
||||||
|
import { parseTimestamp, adjustQualityForXRP } from "./utils";
|
||||||
|
|
||||||
|
export interface FormattedAccountOrder {
|
||||||
|
specification: FormattedOrderSpecification;
|
||||||
properties: {
|
properties: {
|
||||||
maker: string
|
maker: string;
|
||||||
sequence: number
|
sequence: number;
|
||||||
makerExchangeRate: string
|
makerExchangeRate: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this function once rippled provides quality directly
|
// TODO: remove this function once rippled provides quality directly
|
||||||
function computeQuality(takerGets, takerPays) {
|
function computeQuality(takerGets, takerPays) {
|
||||||
const quotient = new BigNumber(takerPays.value).dividedBy(takerGets.value)
|
const quotient = new BigNumber(takerPays.value).dividedBy(takerGets.value);
|
||||||
return quotient.precision(16, BigNumber.ROUND_HALF_UP).toString()
|
return quotient.precision(16, BigNumber.ROUND_HALF_UP).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// rippled 'account_offers' returns a different format for orders than 'tx'
|
// rippled 'account_offers' returns a different format for orders than 'tx'
|
||||||
@@ -26,22 +28,22 @@ export function parseAccountOrder(
|
|||||||
address: string,
|
address: string,
|
||||||
order: any
|
order: any
|
||||||
): FormattedAccountOrder {
|
): FormattedAccountOrder {
|
||||||
const direction = (order.flags & orderFlags.Sell) === 0 ? 'buy' : 'sell'
|
const direction = (order.flags & orderFlags.Sell) === 0 ? "buy" : "sell";
|
||||||
const takerGetsAmount = parseAmount(order.taker_gets)
|
const takerGetsAmount = parseAmount(order.taker_gets);
|
||||||
const takerPaysAmount = parseAmount(order.taker_pays)
|
const takerPaysAmount = parseAmount(order.taker_pays);
|
||||||
const quantity = direction === 'buy' ? takerPaysAmount : takerGetsAmount
|
const quantity = direction === "buy" ? takerPaysAmount : takerGetsAmount;
|
||||||
const totalPrice = direction === 'buy' ? takerGetsAmount : takerPaysAmount
|
const totalPrice = direction === "buy" ? takerGetsAmount : takerPaysAmount;
|
||||||
|
|
||||||
// note: immediateOrCancel and fillOrKill orders cannot enter the order book
|
// note: immediateOrCancel and fillOrKill orders cannot enter the order book
|
||||||
// so we can omit those flags here
|
// so we can omit those flags here
|
||||||
const specification = removeUndefined({
|
const specification = removeUndefined({
|
||||||
direction: direction,
|
direction,
|
||||||
quantity: quantity,
|
quantity,
|
||||||
totalPrice: totalPrice,
|
totalPrice,
|
||||||
passive: (order.flags & orderFlags.Passive) !== 0 || undefined,
|
passive: (order.flags & orderFlags.Passive) !== 0 || undefined,
|
||||||
// rippled currently does not provide "expiration" in account_offers
|
// rippled currently does not provide "expiration" in account_offers
|
||||||
expirationTime: parseTimestamp(order.expiration)
|
expirationTime: parseTimestamp(order.expiration),
|
||||||
})
|
});
|
||||||
|
|
||||||
const makerExchangeRate = order.quality
|
const makerExchangeRate = order.quality
|
||||||
? adjustQualityForXRP(
|
? adjustQualityForXRP(
|
||||||
@@ -49,12 +51,12 @@ export function parseAccountOrder(
|
|||||||
takerGetsAmount.currency,
|
takerGetsAmount.currency,
|
||||||
takerPaysAmount.currency
|
takerPaysAmount.currency
|
||||||
)
|
)
|
||||||
: computeQuality(takerGetsAmount, takerPaysAmount)
|
: computeQuality(takerGetsAmount, takerPaysAmount);
|
||||||
const properties = {
|
const properties = {
|
||||||
maker: address,
|
maker: address,
|
||||||
sequence: order.seq,
|
sequence: order.seq,
|
||||||
makerExchangeRate: makerExchangeRate
|
makerExchangeRate,
|
||||||
}
|
};
|
||||||
|
|
||||||
return {specification, properties}
|
return { specification, properties };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import {parseQuality} from './utils'
|
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
import {
|
import {
|
||||||
Trustline,
|
Trustline,
|
||||||
FormattedTrustline
|
FormattedTrustline,
|
||||||
} from '../../common/types/objects/trustlines'
|
} from "../../common/types/objects/trustlines";
|
||||||
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import { parseQuality } from "./utils";
|
||||||
|
|
||||||
// rippled 'account_lines' returns a different format for
|
// rippled 'account_lines' returns a different format for
|
||||||
// trustlines than 'tx'
|
// trustlines than 'tx'
|
||||||
@@ -16,19 +17,19 @@ function parseAccountTrustline(trustline: Trustline): FormattedTrustline {
|
|||||||
qualityOut: parseQuality(trustline.quality_out) || undefined,
|
qualityOut: parseQuality(trustline.quality_out) || undefined,
|
||||||
ripplingDisabled: trustline.no_ripple,
|
ripplingDisabled: trustline.no_ripple,
|
||||||
frozen: trustline.freeze,
|
frozen: trustline.freeze,
|
||||||
authorized: trustline.authorized
|
authorized: trustline.authorized,
|
||||||
})
|
});
|
||||||
// rippled doesn't provide the counterparty's qualities
|
// rippled doesn't provide the counterparty's qualities
|
||||||
const counterparty = removeUndefined({
|
const counterparty = removeUndefined({
|
||||||
limit: trustline.limit_peer,
|
limit: trustline.limit_peer,
|
||||||
ripplingDisabled: trustline.no_ripple_peer,
|
ripplingDisabled: trustline.no_ripple_peer,
|
||||||
frozen: trustline.freeze_peer,
|
frozen: trustline.freeze_peer,
|
||||||
authorized: trustline.peer_authorized
|
authorized: trustline.peer_authorized,
|
||||||
})
|
});
|
||||||
const state = {
|
const state = {
|
||||||
balance: trustline.balance
|
balance: trustline.balance,
|
||||||
}
|
};
|
||||||
return {specification, counterparty, state}
|
return { specification, counterparty, state };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseAccountTrustline
|
export default parseAccountTrustline;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
function parseAmendment(tx: any) {
|
function parseAmendment(tx: any) {
|
||||||
return {
|
return {
|
||||||
amendment: tx.Amendment
|
amendment: tx.Amendment,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseAmendment
|
export default parseAmendment;
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import {Amount, RippledAmount} from '../../common/types/objects'
|
import { Amount, RippledAmount } from "../../common/types/objects";
|
||||||
import {dropsToXrp} from '../../utils'
|
import { dropsToXrp } from "../../utils";
|
||||||
|
|
||||||
function parseAmount(amount: RippledAmount): Amount {
|
function parseAmount(amount: RippledAmount): Amount {
|
||||||
if (typeof amount === 'string') {
|
if (typeof amount === "string") {
|
||||||
return {
|
return {
|
||||||
currency: 'XRP',
|
currency: "XRP",
|
||||||
value: dropsToXrp(amount)
|
value: dropsToXrp(amount),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
currency: amount.currency,
|
currency: amount.currency,
|
||||||
value: amount.value,
|
value: amount.value,
|
||||||
counterparty: amount.issuer
|
counterparty: amount.issuer,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseAmount
|
export default parseAmount;
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {parseMemos} from './utils'
|
|
||||||
|
import { parseMemos } from "./utils";
|
||||||
|
|
||||||
function parseOrderCancellation(tx: any): object {
|
function parseOrderCancellation(tx: any): object {
|
||||||
assert.ok(tx.TransactionType === 'OfferCancel')
|
assert.ok(tx.TransactionType === "OfferCancel");
|
||||||
return {
|
return {
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
orderSequence: tx.OfferSequence
|
orderSequence: tx.OfferSequence,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseOrderCancellation
|
export default parseOrderCancellation;
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
import {parseMemos} from './utils'
|
|
||||||
|
|
||||||
export type FormattedCheckCancel = {
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import { parseMemos } from "./utils";
|
||||||
|
|
||||||
|
export interface FormattedCheckCancel {
|
||||||
// ID of the Check ledger object to cancel.
|
// ID of the Check ledger object to cancel.
|
||||||
checkID: string
|
checkID: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCheckCancel(tx: any): FormattedCheckCancel {
|
function parseCheckCancel(tx: any): FormattedCheckCancel {
|
||||||
assert.ok(tx.TransactionType === 'CheckCancel')
|
assert.ok(tx.TransactionType === "CheckCancel");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
checkID: tx.CheckID
|
checkID: tx.CheckID,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseCheckCancel
|
export default parseCheckCancel;
|
||||||
|
|||||||
@@ -1,36 +1,38 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
import parseAmount from './amount'
|
|
||||||
import {Amount} from '../../common/types/objects'
|
|
||||||
import {parseMemos} from './utils'
|
|
||||||
|
|
||||||
export type FormattedCheckCash = {
|
import { Amount } from "../../common/types/objects";
|
||||||
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import parseAmount from "./amount";
|
||||||
|
import { parseMemos } from "./utils";
|
||||||
|
|
||||||
|
export interface FormattedCheckCash {
|
||||||
// ID of the Check ledger object to cash.
|
// ID of the Check ledger object to cash.
|
||||||
checkID: string
|
checkID: string;
|
||||||
|
|
||||||
// (Optional) redeem the Check for exactly this amount, if possible.
|
// (Optional) redeem the Check for exactly this amount, if possible.
|
||||||
// The currency must match that of the `SendMax` of the corresponding
|
// The currency must match that of the `SendMax` of the corresponding
|
||||||
// `CheckCreate` transaction.
|
// `CheckCreate` transaction.
|
||||||
amount: Amount
|
amount: Amount;
|
||||||
|
|
||||||
// (Optional) redeem the Check for at least this amount and
|
// (Optional) redeem the Check for at least this amount and
|
||||||
// for as much as possible.
|
// for as much as possible.
|
||||||
// The currency must match that of the `SendMax` of the corresponding
|
// The currency must match that of the `SendMax` of the corresponding
|
||||||
// `CheckCreate` transaction.
|
// `CheckCreate` transaction.
|
||||||
deliverMin: Amount
|
deliverMin: Amount;
|
||||||
|
|
||||||
// *must* include either Amount or DeliverMin, but not both.
|
// *must* include either Amount or DeliverMin, but not both.
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCheckCash(tx: any): FormattedCheckCash {
|
function parseCheckCash(tx: any): FormattedCheckCash {
|
||||||
assert.ok(tx.TransactionType === 'CheckCash')
|
assert.ok(tx.TransactionType === "CheckCash");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
checkID: tx.CheckID,
|
checkID: tx.CheckID,
|
||||||
amount: tx.Amount && parseAmount(tx.Amount),
|
amount: tx.Amount && parseAmount(tx.Amount),
|
||||||
deliverMin: tx.DeliverMin && parseAmount(tx.DeliverMin)
|
deliverMin: tx.DeliverMin && parseAmount(tx.DeliverMin),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseCheckCash
|
export default parseCheckCash;
|
||||||
|
|||||||
@@ -1,30 +1,31 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {parseTimestamp} from './utils'
|
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
import parseAmount from './amount'
|
|
||||||
import {Amount} from '../../common/types/objects'
|
|
||||||
import {parseMemos} from './utils'
|
|
||||||
|
|
||||||
export type FormattedCheckCreate = {
|
import { Amount } from "../../common/types/objects";
|
||||||
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import parseAmount from "./amount";
|
||||||
|
import { parseTimestamp, parseMemos } from "./utils";
|
||||||
|
|
||||||
|
export interface FormattedCheckCreate {
|
||||||
// account that can cash the check.
|
// account that can cash the check.
|
||||||
destination: string
|
destination: string;
|
||||||
|
|
||||||
// amount the check is allowed to debit the sender,
|
// amount the check is allowed to debit the sender,
|
||||||
// including transfer fees on non-XRP currencies.
|
// including transfer fees on non-XRP currencies.
|
||||||
sendMax: Amount
|
sendMax: Amount;
|
||||||
|
|
||||||
// (Optional) identifies the reason for the check, or a hosted recipient.
|
// (Optional) identifies the reason for the check, or a hosted recipient.
|
||||||
destinationTag?: string
|
destinationTag?: string;
|
||||||
|
|
||||||
// (Optional) time in seconds since the Ripple Epoch.
|
// (Optional) time in seconds since the Ripple Epoch.
|
||||||
expiration?: string
|
expiration?: string;
|
||||||
|
|
||||||
// (Optional) 256-bit hash representing a specific reason or identifier.
|
// (Optional) 256-bit hash representing a specific reason or identifier.
|
||||||
invoiceID?: string
|
invoiceID?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCheckCreate(tx: any): FormattedCheckCreate {
|
function parseCheckCreate(tx: any): FormattedCheckCreate {
|
||||||
assert.ok(tx.TransactionType === 'CheckCreate')
|
assert.ok(tx.TransactionType === "CheckCreate");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
@@ -32,8 +33,8 @@ function parseCheckCreate(tx: any): FormattedCheckCreate {
|
|||||||
sendMax: parseAmount(tx.SendMax),
|
sendMax: parseAmount(tx.SendMax),
|
||||||
destinationTag: tx.DestinationTag,
|
destinationTag: tx.DestinationTag,
|
||||||
expiration: tx.Expiration && parseTimestamp(tx.Expiration),
|
expiration: tx.Expiration && parseTimestamp(tx.Expiration),
|
||||||
invoiceID: tx.InvoiceID
|
invoiceID: tx.InvoiceID,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseCheckCreate
|
export default parseCheckCreate;
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
import {parseMemos} from './utils'
|
|
||||||
|
|
||||||
export type FormattedDepositPreauth = {
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import { parseMemos } from "./utils";
|
||||||
|
|
||||||
|
export interface FormattedDepositPreauth {
|
||||||
// account (address) of the sender to preauthorize
|
// account (address) of the sender to preauthorize
|
||||||
authorize: string
|
authorize: string;
|
||||||
|
|
||||||
// account (address) of the sender whose preauthorization should be revoked
|
// account (address) of the sender whose preauthorization should be revoked
|
||||||
unauthorize: string
|
unauthorize: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDepositPreauth(tx: any): FormattedDepositPreauth {
|
function parseDepositPreauth(tx: any): FormattedDepositPreauth {
|
||||||
assert.ok(tx.TransactionType === 'DepositPreauth')
|
assert.ok(tx.TransactionType === "DepositPreauth");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
authorize: tx.Authorize,
|
authorize: tx.Authorize,
|
||||||
unauthorize: tx.Unauthorize
|
unauthorize: tx.Unauthorize,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseDepositPreauth
|
export default parseDepositPreauth;
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {parseMemos} from './utils'
|
|
||||||
import {removeUndefined} from '../../utils'
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import { parseMemos } from "./utils";
|
||||||
|
|
||||||
function parseEscrowCancellation(tx: any): object {
|
function parseEscrowCancellation(tx: any): object {
|
||||||
assert.ok(tx.TransactionType === 'EscrowCancel')
|
assert.ok(tx.TransactionType === "EscrowCancel");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
owner: tx.Owner,
|
owner: tx.Owner,
|
||||||
escrowSequence: tx.OfferSequence
|
escrowSequence: tx.OfferSequence,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseEscrowCancellation
|
export default parseEscrowCancellation;
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import parseAmount from './amount'
|
|
||||||
import {parseTimestamp, parseMemos} from './utils'
|
import { removeUndefined } from "../../utils";
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
|
import parseAmount from "./amount";
|
||||||
|
import { parseTimestamp, parseMemos } from "./utils";
|
||||||
|
|
||||||
function parseEscrowCreation(tx: any): object {
|
function parseEscrowCreation(tx: any): object {
|
||||||
assert.ok(tx.TransactionType === 'EscrowCreate')
|
assert.ok(tx.TransactionType === "EscrowCreate");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
amount: parseAmount(tx.Amount).value,
|
amount: parseAmount(tx.Amount).value,
|
||||||
@@ -14,8 +16,8 @@ function parseEscrowCreation(tx: any): object {
|
|||||||
allowCancelAfter: parseTimestamp(tx.CancelAfter),
|
allowCancelAfter: parseTimestamp(tx.CancelAfter),
|
||||||
allowExecuteAfter: parseTimestamp(tx.FinishAfter),
|
allowExecuteAfter: parseTimestamp(tx.FinishAfter),
|
||||||
sourceTag: tx.SourceTag,
|
sourceTag: tx.SourceTag,
|
||||||
destinationTag: tx.DestinationTag
|
destinationTag: tx.DestinationTag,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseEscrowCreation
|
export default parseEscrowCreation;
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {parseMemos} from './utils'
|
|
||||||
import {removeUndefined} from '../../utils'
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import { parseMemos } from "./utils";
|
||||||
|
|
||||||
function parseEscrowExecution(tx: any): object {
|
function parseEscrowExecution(tx: any): object {
|
||||||
assert.ok(tx.TransactionType === 'EscrowFinish')
|
assert.ok(tx.TransactionType === "EscrowFinish");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
owner: tx.Owner,
|
owner: tx.Owner,
|
||||||
escrowSequence: tx.OfferSequence,
|
escrowSequence: tx.OfferSequence,
|
||||||
condition: tx.Condition,
|
condition: tx.Condition,
|
||||||
fulfillment: tx.Fulfillment
|
fulfillment: tx.Fulfillment,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseEscrowExecution
|
export default parseEscrowExecution;
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from "bignumber.js";
|
||||||
import {dropsToXrp} from '../../utils'
|
|
||||||
import {parseMemos} from './utils'
|
import { dropsToXrp } from "../../utils";
|
||||||
|
|
||||||
|
import { parseMemos } from "./utils";
|
||||||
|
|
||||||
function parseFeeUpdate(tx: any) {
|
function parseFeeUpdate(tx: any) {
|
||||||
const baseFeeDrops = new BigNumber(tx.BaseFee, 16).toString()
|
const baseFeeDrops = new BigNumber(tx.BaseFee, 16).toString();
|
||||||
return {
|
return {
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
baseFeeXRP: dropsToXrp(baseFeeDrops),
|
baseFeeXRP: dropsToXrp(baseFeeDrops),
|
||||||
referenceFeeUnits: tx.ReferenceFeeUnits,
|
referenceFeeUnits: tx.ReferenceFeeUnits,
|
||||||
reserveBaseXRP: dropsToXrp(tx.ReserveBase),
|
reserveBaseXRP: dropsToXrp(tx.ReserveBase),
|
||||||
reserveIncrementXRP: dropsToXrp(tx.ReserveIncrement)
|
reserveIncrementXRP: dropsToXrp(tx.ReserveIncrement),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseFeeUpdate
|
export default parseFeeUpdate;
|
||||||
|
|||||||
@@ -1,52 +1,54 @@
|
|||||||
import _ from 'lodash'
|
import BigNumber from "bignumber.js";
|
||||||
import BigNumber from 'bignumber.js'
|
import _ from "lodash";
|
||||||
import {constants} from '../../common'
|
|
||||||
const AccountFields = constants.AccountFields
|
import { constants } from "../../common";
|
||||||
|
|
||||||
|
const AccountFields = constants.AccountFields;
|
||||||
|
|
||||||
function parseField(info, value) {
|
function parseField(info, value) {
|
||||||
if (info.encoding === 'hex' && !info.length) {
|
if (info.encoding === "hex" && !info.length) {
|
||||||
// e.g. "domain"
|
// e.g. "domain"
|
||||||
return Buffer.from(value, 'hex').toString('ascii')
|
return Buffer.from(value, "hex").toString("ascii");
|
||||||
}
|
}
|
||||||
if (info.shift) {
|
if (info.shift) {
|
||||||
return new BigNumber(value).shiftedBy(-info.shift).toNumber()
|
return new BigNumber(value).shiftedBy(-info.shift).toNumber();
|
||||||
}
|
}
|
||||||
return value
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseFields(data: any): object {
|
function parseFields(data: any): object {
|
||||||
const settings: any = {}
|
const settings: any = {};
|
||||||
for (const fieldName in AccountFields) {
|
for (const fieldName in AccountFields) {
|
||||||
const fieldValue = data[fieldName]
|
const fieldValue = data[fieldName];
|
||||||
if (fieldValue != null) {
|
if (fieldValue != null) {
|
||||||
const info = AccountFields[fieldName]
|
const info = AccountFields[fieldName];
|
||||||
settings[info.name] = parseField(info, fieldValue)
|
settings[info.name] = parseField(info, fieldValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.RegularKey) {
|
if (data.RegularKey) {
|
||||||
settings.regularKey = data.RegularKey
|
settings.regularKey = data.RegularKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since an account can own at most one SignerList,
|
// Since an account can own at most one SignerList,
|
||||||
// this array must have exactly one member if it is present.
|
// this array must have exactly one member if it is present.
|
||||||
if (data.signer_lists && data.signer_lists.length === 1) {
|
if (data.signer_lists && data.signer_lists.length === 1) {
|
||||||
settings.signers = {}
|
settings.signers = {};
|
||||||
if (data.signer_lists[0].SignerQuorum) {
|
if (data.signer_lists[0].SignerQuorum) {
|
||||||
settings.signers.threshold = data.signer_lists[0].SignerQuorum
|
settings.signers.threshold = data.signer_lists[0].SignerQuorum;
|
||||||
}
|
}
|
||||||
if (data.signer_lists[0].SignerEntries) {
|
if (data.signer_lists[0].SignerEntries) {
|
||||||
settings.signers.weights = data.signer_lists[0].SignerEntries.map(
|
settings.signers.weights = data.signer_lists[0].SignerEntries.map(
|
||||||
(entry: any) => {
|
(entry: any) => {
|
||||||
return {
|
return {
|
||||||
address: entry.SignerEntry.Account,
|
address: entry.SignerEntry.Account,
|
||||||
weight: entry.SignerEntry.SignerWeight
|
weight: entry.SignerEntry.SignerWeight,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseFields
|
export default parseFields;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const orderFlags = {
|
const orderFlags = {
|
||||||
Passive: 0x00010000,
|
Passive: 0x00010000,
|
||||||
Sell: 0x00020000 // offer was placed as a sell
|
Sell: 0x00020000, // offer was placed as a sell
|
||||||
}
|
};
|
||||||
|
|
||||||
const trustlineFlags = {
|
const trustlineFlags = {
|
||||||
LowReserve: 0x00010000, // entry counts toward reserve
|
LowReserve: 0x00010000, // entry counts toward reserve
|
||||||
@@ -11,7 +11,7 @@ const trustlineFlags = {
|
|||||||
LowNoRipple: 0x00100000,
|
LowNoRipple: 0x00100000,
|
||||||
HighNoRipple: 0x00200000,
|
HighNoRipple: 0x00200000,
|
||||||
LowFreeze: 0x00400000,
|
LowFreeze: 0x00400000,
|
||||||
HighFreeze: 0x00800000
|
HighFreeze: 0x00800000,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {orderFlags, trustlineFlags}
|
export { orderFlags, trustlineFlags };
|
||||||
|
|||||||
@@ -1,87 +1,92 @@
|
|||||||
import _ from 'lodash'
|
import _ from "lodash";
|
||||||
import {removeUndefined, rippleTimeToISOTime} from '../../utils'
|
|
||||||
import parseTransaction from './transaction'
|
|
||||||
import { TransactionAndMetadata } from '../../models/transactions'
|
|
||||||
|
|
||||||
export type FormattedLedger = {
|
import { TransactionAndMetadata } from "../../models/transactions";
|
||||||
|
import { removeUndefined, rippleTimeToISOTime } from "../../utils";
|
||||||
|
|
||||||
|
import parseTransaction from "./transaction";
|
||||||
|
|
||||||
|
export interface FormattedLedger {
|
||||||
// TODO: properties in type don't match response object. Fix!
|
// TODO: properties in type don't match response object. Fix!
|
||||||
// closed: boolean,
|
// closed: boolean,
|
||||||
stateHash: string
|
stateHash: string;
|
||||||
closeTime: string
|
closeTime: string;
|
||||||
closeTimeResolution: number
|
closeTimeResolution: number;
|
||||||
closeFlags: number
|
closeFlags: number;
|
||||||
ledgerHash: string
|
ledgerHash: string;
|
||||||
ledgerVersion: number
|
ledgerVersion: number;
|
||||||
parentLedgerHash: string
|
parentLedgerHash: string;
|
||||||
parentCloseTime: string
|
parentCloseTime: string;
|
||||||
totalDrops: string
|
totalDrops: string;
|
||||||
transactionHash: string
|
transactionHash: string;
|
||||||
transactions?: Array<object>
|
transactions?: object[];
|
||||||
transactionHashes?: Array<string>
|
transactionHashes?: string[];
|
||||||
rawState?: string
|
rawState?: string;
|
||||||
stateHashes?: Array<string>
|
stateHashes?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTransactionWrapper(ledgerVersion: number, tx: TransactionAndMetadata) {
|
function parseTransactionWrapper(
|
||||||
|
ledgerVersion: number,
|
||||||
|
tx: TransactionAndMetadata
|
||||||
|
) {
|
||||||
// renames metaData to meta and adds ledger_index
|
// renames metaData to meta and adds ledger_index
|
||||||
const transaction = Object.assign({}, _.omit(tx, 'metadata'), {
|
const transaction = {
|
||||||
|
..._.omit(tx, "metadata"),
|
||||||
meta: tx.metadata,
|
meta: tx.metadata,
|
||||||
ledger_index: ledgerVersion
|
ledger_index: ledgerVersion,
|
||||||
})
|
};
|
||||||
const result = parseTransaction(transaction, true)
|
const result = parseTransaction(transaction, true);
|
||||||
if (!result.outcome.ledgerVersion) {
|
if (!result.outcome.ledgerVersion) {
|
||||||
result.outcome.ledgerVersion = ledgerVersion
|
result.outcome.ledgerVersion = ledgerVersion;
|
||||||
}
|
}
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTransactions(transactions: string[] | TransactionAndMetadata[], ledgerVersion: number) {
|
function parseTransactions(
|
||||||
|
transactions: string[] | TransactionAndMetadata[],
|
||||||
|
ledgerVersion: number
|
||||||
|
) {
|
||||||
if (_.isEmpty(transactions)) {
|
if (_.isEmpty(transactions)) {
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
if (typeof transactions[0] === 'string') {
|
if (typeof transactions[0] === "string") {
|
||||||
return {transactionHashes: transactions as unknown as string[]}
|
return { transactionHashes: transactions as unknown as string[] };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
transactions: (transactions as unknown as TransactionAndMetadata[]).map(
|
transactions: (transactions as unknown as TransactionAndMetadata[]).map(
|
||||||
_.partial(parseTransactionWrapper, ledgerVersion)
|
_.partial(parseTransactionWrapper, ledgerVersion)
|
||||||
)
|
),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseState(state) {
|
function parseState(state) {
|
||||||
if (_.isEmpty(state)) {
|
if (_.isEmpty(state)) {
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
if (typeof state[0] === 'string') {
|
if (typeof state[0] === "string") {
|
||||||
return {stateHashes: state}
|
return { stateHashes: state };
|
||||||
}
|
}
|
||||||
return {rawState: JSON.stringify(state)}
|
return { rawState: JSON.stringify(state) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Ledger} ledger must be a *closed* ledger with valid `close_time` and `parent_close_time`
|
* @param ledger - Must be a *closed* ledger with valid `close_time` and `parent_close_time`.
|
||||||
* @returns {FormattedLedger} formatted ledger
|
* @returns Formatted ledger.
|
||||||
* @throws RangeError: Invalid time value (rippleTimeToISOTime)
|
* @throws RangeError: Invalid time value (rippleTimeToISOTime).
|
||||||
*/
|
*/
|
||||||
export function parseLedger(ledger): FormattedLedger {
|
export function parseLedger(ledger): FormattedLedger {
|
||||||
const ledgerVersion = parseInt(ledger.ledger_index, 10)
|
const ledgerVersion = parseInt(ledger.ledger_index, 10);
|
||||||
return removeUndefined(
|
return removeUndefined({
|
||||||
Object.assign(
|
stateHash: ledger.account_hash,
|
||||||
{
|
closeTime: rippleTimeToISOTime(ledger.close_time),
|
||||||
stateHash: ledger.account_hash,
|
closeTimeResolution: ledger.close_time_resolution,
|
||||||
closeTime: rippleTimeToISOTime(ledger.close_time),
|
closeFlags: ledger.close_flags,
|
||||||
closeTimeResolution: ledger.close_time_resolution,
|
ledgerHash: ledger.ledger_hash,
|
||||||
closeFlags: ledger.close_flags,
|
ledgerVersion,
|
||||||
ledgerHash: ledger.ledger_hash,
|
parentLedgerHash: ledger.parent_hash,
|
||||||
ledgerVersion: ledgerVersion,
|
parentCloseTime: rippleTimeToISOTime(ledger.parent_close_time),
|
||||||
parentLedgerHash: ledger.parent_hash,
|
totalDrops: ledger.total_coins,
|
||||||
parentCloseTime: rippleTimeToISOTime(ledger.parent_close_time),
|
transactionHash: ledger.transaction_hash,
|
||||||
totalDrops: ledger.total_coins,
|
...parseTransactions(ledger.transactions, ledgerVersion),
|
||||||
transactionHash: ledger.transaction_hash
|
...parseState(ledger.accountState),
|
||||||
},
|
});
|
||||||
parseTransactions(ledger.transactions, ledgerVersion),
|
|
||||||
parseState(ledger.accountState)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,36 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {parseTimestamp} from './utils'
|
|
||||||
import {parseMemos} from './utils'
|
import { txFlags } from "../../common";
|
||||||
import parseAmount from './amount'
|
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
import {txFlags} from '../../common'
|
|
||||||
import {
|
import {
|
||||||
FormattedOrderSpecification,
|
FormattedOrderSpecification,
|
||||||
OfferCreateTransaction
|
OfferCreateTransaction,
|
||||||
} from '../../common/types/objects/index'
|
} from "../../common/types/objects/index";
|
||||||
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
const flags = txFlags.OfferCreate
|
import parseAmount from "./amount";
|
||||||
|
import { parseTimestamp, parseMemos } from "./utils";
|
||||||
|
|
||||||
|
const flags = txFlags.OfferCreate;
|
||||||
|
|
||||||
function parseOrder(tx: OfferCreateTransaction): FormattedOrderSpecification {
|
function parseOrder(tx: OfferCreateTransaction): FormattedOrderSpecification {
|
||||||
assert.ok(tx.TransactionType === 'OfferCreate')
|
assert.ok(tx.TransactionType === "OfferCreate");
|
||||||
|
|
||||||
const direction = (tx.Flags & flags.Sell) === 0 ? 'buy' : 'sell'
|
const direction = (tx.Flags & flags.Sell) === 0 ? "buy" : "sell";
|
||||||
const takerGetsAmount = parseAmount(tx.TakerGets)
|
const takerGetsAmount = parseAmount(tx.TakerGets);
|
||||||
const takerPaysAmount = parseAmount(tx.TakerPays)
|
const takerPaysAmount = parseAmount(tx.TakerPays);
|
||||||
const quantity = direction === 'buy' ? takerPaysAmount : takerGetsAmount
|
const quantity = direction === "buy" ? takerPaysAmount : takerGetsAmount;
|
||||||
const totalPrice = direction === 'buy' ? takerGetsAmount : takerPaysAmount
|
const totalPrice = direction === "buy" ? takerGetsAmount : takerPaysAmount;
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
direction: direction,
|
direction,
|
||||||
quantity: quantity,
|
quantity,
|
||||||
totalPrice: totalPrice,
|
totalPrice,
|
||||||
passive: (tx.Flags & flags.Passive) !== 0 || undefined,
|
passive: (tx.Flags & flags.Passive) !== 0 || undefined,
|
||||||
immediateOrCancel: (tx.Flags & flags.ImmediateOrCancel) !== 0 || undefined,
|
immediateOrCancel: (tx.Flags & flags.ImmediateOrCancel) !== 0 || undefined,
|
||||||
fillOrKill: (tx.Flags & flags.FillOrKill) !== 0 || undefined,
|
fillOrKill: (tx.Flags & flags.FillOrKill) !== 0 || undefined,
|
||||||
expirationTime: parseTimestamp(tx.Expiration)
|
expirationTime: parseTimestamp(tx.Expiration),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseOrder
|
export default parseOrder;
|
||||||
|
|||||||
@@ -1,42 +1,50 @@
|
|||||||
import _ from 'lodash'
|
import _ from "lodash";
|
||||||
import {parseTimestamp, adjustQualityForXRP} from './utils'
|
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
|
|
||||||
import {orderFlags} from './flags'
|
import { BookOffer } from "../../common/types/commands";
|
||||||
import parseAmount from './amount'
|
import {
|
||||||
import {BookOffer} from '../../common/types/commands'
|
Amount,
|
||||||
import {Amount, FormattedOrderSpecification} from '../../common/types/objects'
|
FormattedOrderSpecification,
|
||||||
|
} from "../../common/types/objects";
|
||||||
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
export type FormattedOrderbookOrder = {
|
import parseAmount from "./amount";
|
||||||
specification: FormattedOrderSpecification
|
import { orderFlags } from "./flags";
|
||||||
|
import { parseTimestamp, adjustQualityForXRP } from "./utils";
|
||||||
|
|
||||||
|
export interface FormattedOrderbookOrder {
|
||||||
|
specification: FormattedOrderSpecification;
|
||||||
properties: {
|
properties: {
|
||||||
maker: string
|
maker: string;
|
||||||
sequence: number
|
sequence: number;
|
||||||
makerExchangeRate: string
|
makerExchangeRate: string;
|
||||||
}
|
};
|
||||||
state?: {
|
state?: {
|
||||||
fundedAmount: Amount
|
fundedAmount: Amount;
|
||||||
priceOfFundedAmount: Amount
|
priceOfFundedAmount: Amount;
|
||||||
}
|
};
|
||||||
data: BookOffer
|
data: BookOffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseOrderbookOrder(data: BookOffer): FormattedOrderbookOrder {
|
export function parseOrderbookOrder(data: BookOffer): FormattedOrderbookOrder {
|
||||||
const direction = (data.Flags & orderFlags.Sell) === 0 ? 'buy' : 'sell'
|
const direction = (data.Flags & orderFlags.Sell) === 0 ? "buy" : "sell";
|
||||||
const takerGetsAmount = parseAmount(data.TakerGets)
|
const takerGetsAmount = parseAmount(data.TakerGets);
|
||||||
const takerPaysAmount = parseAmount(data.TakerPays)
|
const takerPaysAmount = parseAmount(data.TakerPays);
|
||||||
const quantity = direction === 'buy' ? takerPaysAmount : takerGetsAmount
|
const quantity = direction === "buy" ? takerPaysAmount : takerGetsAmount;
|
||||||
const totalPrice = direction === 'buy' ? takerGetsAmount : takerPaysAmount
|
const totalPrice = direction === "buy" ? takerGetsAmount : takerPaysAmount;
|
||||||
|
|
||||||
// note: immediateOrCancel and fillOrKill orders cannot enter the order book
|
// note: immediateOrCancel and fillOrKill orders cannot enter the order book
|
||||||
// so we can omit those flags here
|
// so we can omit those flags here
|
||||||
const specification: FormattedOrderSpecification = removeUndefined({
|
const specification: FormattedOrderSpecification = removeUndefined({
|
||||||
direction: direction,
|
direction,
|
||||||
quantity: quantity,
|
quantity,
|
||||||
totalPrice: totalPrice,
|
totalPrice,
|
||||||
passive: (data.Flags & orderFlags.Passive) !== 0 || undefined,
|
passive: (data.Flags & orderFlags.Passive) !== 0 || undefined,
|
||||||
expirationTime: parseTimestamp(data.Expiration)
|
expirationTime: parseTimestamp(data.Expiration),
|
||||||
})
|
});
|
||||||
|
|
||||||
|
if (data.quality == null) {
|
||||||
|
throw new Error("parseOrderBookOrder: Could not find quality");
|
||||||
|
}
|
||||||
|
|
||||||
const properties = {
|
const properties = {
|
||||||
maker: data.Account,
|
maker: data.Account,
|
||||||
@@ -45,19 +53,25 @@ export function parseOrderbookOrder(data: BookOffer): FormattedOrderbookOrder {
|
|||||||
data.quality,
|
data.quality,
|
||||||
takerGetsAmount.currency,
|
takerGetsAmount.currency,
|
||||||
takerPaysAmount.currency
|
takerPaysAmount.currency
|
||||||
)
|
),
|
||||||
}
|
};
|
||||||
|
|
||||||
const takerGetsFunded = data.taker_gets_funded
|
const takerGetsFunded = data.taker_gets_funded
|
||||||
? parseAmount(data.taker_gets_funded)
|
? parseAmount(data.taker_gets_funded)
|
||||||
: undefined
|
: undefined;
|
||||||
const takerPaysFunded = data.taker_pays_funded
|
const takerPaysFunded = data.taker_pays_funded
|
||||||
? parseAmount(data.taker_pays_funded)
|
? parseAmount(data.taker_pays_funded)
|
||||||
: undefined
|
: undefined;
|
||||||
const available = removeUndefined({
|
const available = removeUndefined({
|
||||||
fundedAmount: takerGetsFunded,
|
fundedAmount: takerGetsFunded,
|
||||||
priceOfFundedAmount: takerPaysFunded
|
priceOfFundedAmount: takerPaysFunded,
|
||||||
})
|
});
|
||||||
const state = _.isEmpty(available) ? undefined : available
|
const state = _.isEmpty(available) ? undefined : available;
|
||||||
return removeUndefined({specification, properties, state, data})
|
|
||||||
|
return removeUndefined({
|
||||||
|
specification,
|
||||||
|
properties,
|
||||||
|
state,
|
||||||
|
data,
|
||||||
|
}) as FormattedOrderbookOrder;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,33 @@
|
|||||||
import _ from 'lodash'
|
import _ from "lodash";
|
||||||
import parseAmount from './amount'
|
|
||||||
import {Amount, RippledAmount} from '../../common/types/objects'
|
import { Amount, RippledAmount } from "../../common/types/objects";
|
||||||
import {Path, GetPaths, RippledPathsResponse} from '../pathfind-types'
|
import { Path, GetPaths, RippledPathsResponse } from "../pathfind-types";
|
||||||
|
|
||||||
|
import parseAmount from "./amount";
|
||||||
|
|
||||||
function parsePaths(paths) {
|
function parsePaths(paths) {
|
||||||
return paths.map((steps) =>
|
return paths.map((steps) =>
|
||||||
steps.map((step) => _.omit(step, ['type', 'type_hex']))
|
steps.map((step) => _.omit(step, ["type", "type_hex"]))
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeAnyCounterpartyEncoding(address: string, amount: Amount) {
|
function removeAnyCounterpartyEncoding(address: string, amount: Amount) {
|
||||||
return amount.counterparty === address
|
return amount.counterparty === address
|
||||||
? _.omit(amount, 'counterparty')
|
? _.omit(amount, "counterparty")
|
||||||
: amount
|
: amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAdjustment(
|
function createAdjustment(
|
||||||
address: string,
|
address: string,
|
||||||
adjustmentWithoutAddress: object
|
adjustmentWithoutAddress: object
|
||||||
): any {
|
): any {
|
||||||
const amountKey = Object.keys(adjustmentWithoutAddress)[0]
|
const amountKey = Object.keys(adjustmentWithoutAddress)[0];
|
||||||
const amount = adjustmentWithoutAddress[amountKey]
|
const amount = adjustmentWithoutAddress[amountKey];
|
||||||
return _.set(
|
return _.set(
|
||||||
{address: address},
|
{ address },
|
||||||
amountKey,
|
amountKey,
|
||||||
removeAnyCounterpartyEncoding(address, amount)
|
removeAnyCounterpartyEncoding(address, amount)
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseAlternative(
|
function parseAlternative(
|
||||||
@@ -39,28 +41,30 @@ function parseAlternative(
|
|||||||
const amounts =
|
const amounts =
|
||||||
alternative.destination_amount != null
|
alternative.destination_amount != null
|
||||||
? {
|
? {
|
||||||
source: {amount: parseAmount(alternative.source_amount)},
|
source: { amount: parseAmount(alternative.source_amount) },
|
||||||
destination: {minAmount: parseAmount(alternative.destination_amount)}
|
destination: {
|
||||||
|
minAmount: parseAmount(alternative.destination_amount),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
source: {maxAmount: parseAmount(alternative.source_amount)},
|
source: { maxAmount: parseAmount(alternative.source_amount) },
|
||||||
destination: {amount: parseAmount(destinationAmount)}
|
destination: { amount: parseAmount(destinationAmount) },
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
source: createAdjustment(sourceAddress, amounts.source),
|
source: createAdjustment(sourceAddress, amounts.source),
|
||||||
destination: createAdjustment(destinationAddress, amounts.destination),
|
destination: createAdjustment(destinationAddress, amounts.destination),
|
||||||
paths: JSON.stringify(parsePaths(alternative.paths_computed))
|
paths: JSON.stringify(parsePaths(alternative.paths_computed)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePathfind(pathfindResult: RippledPathsResponse): GetPaths {
|
function parsePathfind(pathfindResult: RippledPathsResponse): GetPaths {
|
||||||
const sourceAddress = pathfindResult.source_account
|
const sourceAddress = pathfindResult.source_account;
|
||||||
const destinationAddress = pathfindResult.destination_account
|
const destinationAddress = pathfindResult.destination_account;
|
||||||
const destinationAmount = pathfindResult.destination_amount
|
const destinationAmount = pathfindResult.destination_amount;
|
||||||
return pathfindResult.alternatives.map((alt) =>
|
return pathfindResult.alternatives.map((alt) =>
|
||||||
parseAlternative(sourceAddress, destinationAddress, destinationAmount, alt)
|
parseAlternative(sourceAddress, destinationAddress, destinationAmount, alt)
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parsePathfind
|
export default parsePathfind;
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
import {txFlags} from '../../common'
|
import { txFlags } from "../../common";
|
||||||
import parseAmount from './amount'
|
import { removeUndefined } from "../../utils";
|
||||||
import {parseMemos} from './utils'
|
|
||||||
const claimFlags = txFlags.PaymentChannelClaim
|
import parseAmount from "./amount";
|
||||||
|
import { parseMemos } from "./utils";
|
||||||
|
|
||||||
|
const claimFlags = txFlags.PaymentChannelClaim;
|
||||||
|
|
||||||
function parsePaymentChannelClaim(tx: any): object {
|
function parsePaymentChannelClaim(tx: any): object {
|
||||||
assert.ok(tx.TransactionType === 'PaymentChannelClaim')
|
assert.ok(tx.TransactionType === "PaymentChannelClaim");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
@@ -16,8 +19,8 @@ function parsePaymentChannelClaim(tx: any): object {
|
|||||||
signature: tx.Signature,
|
signature: tx.Signature,
|
||||||
publicKey: tx.PublicKey,
|
publicKey: tx.PublicKey,
|
||||||
renew: Boolean(tx.Flags & claimFlags.Renew) || undefined,
|
renew: Boolean(tx.Flags & claimFlags.Renew) || undefined,
|
||||||
close: Boolean(tx.Flags & claimFlags.Close) || undefined
|
close: Boolean(tx.Flags & claimFlags.Close) || undefined,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parsePaymentChannelClaim
|
export default parsePaymentChannelClaim;
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {parseTimestamp,parseMemos} from './utils'
|
|
||||||
import {removeUndefined} from '../../utils'
|
import { removeUndefined } from "../../utils";
|
||||||
import parseAmount from './amount'
|
|
||||||
|
import parseAmount from "./amount";
|
||||||
|
import { parseTimestamp, parseMemos } from "./utils";
|
||||||
|
|
||||||
function parsePaymentChannelCreate(tx: any): object {
|
function parsePaymentChannelCreate(tx: any): object {
|
||||||
assert.ok(tx.TransactionType === 'PaymentChannelCreate')
|
assert.ok(tx.TransactionType === "PaymentChannelCreate");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
@@ -14,8 +16,8 @@ function parsePaymentChannelCreate(tx: any): object {
|
|||||||
publicKey: tx.PublicKey,
|
publicKey: tx.PublicKey,
|
||||||
cancelAfter: tx.CancelAfter && parseTimestamp(tx.CancelAfter),
|
cancelAfter: tx.CancelAfter && parseTimestamp(tx.CancelAfter),
|
||||||
sourceTag: tx.SourceTag,
|
sourceTag: tx.SourceTag,
|
||||||
destinationTag: tx.DestinationTag
|
destinationTag: tx.DestinationTag,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parsePaymentChannelCreate
|
export default parsePaymentChannelCreate;
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {parseTimestamp,parseMemos} from './utils'
|
|
||||||
import {removeUndefined} from '../../utils'
|
import { removeUndefined } from "../../utils";
|
||||||
import parseAmount from './amount'
|
|
||||||
|
import parseAmount from "./amount";
|
||||||
|
import { parseTimestamp, parseMemos } from "./utils";
|
||||||
|
|
||||||
function parsePaymentChannelFund(tx: any): object {
|
function parsePaymentChannelFund(tx: any): object {
|
||||||
assert.ok(tx.TransactionType === 'PaymentChannelFund')
|
assert.ok(tx.TransactionType === "PaymentChannelFund");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
channel: tx.Channel,
|
channel: tx.Channel,
|
||||||
amount: parseAmount(tx.Amount).value,
|
amount: parseAmount(tx.Amount).value,
|
||||||
expiration: tx.Expiration && parseTimestamp(tx.Expiration)
|
expiration: tx.Expiration && parseTimestamp(tx.Expiration),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parsePaymentChannelFund
|
export default parsePaymentChannelFund;
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
import {parseTimestamp, parseMemos} from './utils'
|
import { PayChannel } from "../../models/ledger";
|
||||||
import {removeUndefined, dropsToXrp} from '../../utils'
|
import { removeUndefined, dropsToXrp } from "../../utils";
|
||||||
import { PayChannel } from '../../models/ledger'
|
|
||||||
|
|
||||||
export type FormattedPaymentChannel = {
|
import { parseTimestamp, parseMemos } from "./utils";
|
||||||
account: string
|
|
||||||
amount: string
|
export interface FormattedPaymentChannel {
|
||||||
balance: string
|
account: string;
|
||||||
publicKey: string
|
amount: string;
|
||||||
destination: string
|
balance: string;
|
||||||
settleDelay: number
|
publicKey: string;
|
||||||
expiration?: string
|
destination: string;
|
||||||
cancelAfter?: string
|
settleDelay: number;
|
||||||
sourceTag?: number
|
expiration?: string;
|
||||||
destinationTag?: number
|
cancelAfter?: string;
|
||||||
previousAffectingTransactionID: string
|
sourceTag?: number;
|
||||||
previousAffectingTransactionLedgerVersion: number
|
destinationTag?: number;
|
||||||
|
previousAffectingTransactionID: string;
|
||||||
|
previousAffectingTransactionLedgerVersion: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parsePaymentChannel(
|
export function parsePaymentChannel(data: PayChannel): FormattedPaymentChannel {
|
||||||
data: PayChannel
|
|
||||||
): FormattedPaymentChannel {
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(data),
|
memos: parseMemos(data),
|
||||||
account: data.Account,
|
account: data.Account,
|
||||||
@@ -33,6 +32,6 @@ export function parsePaymentChannel(
|
|||||||
sourceTag: data.SourceTag,
|
sourceTag: data.SourceTag,
|
||||||
destinationTag: data.DestinationTag,
|
destinationTag: data.DestinationTag,
|
||||||
previousAffectingTransactionID: data.PreviousTxnID,
|
previousAffectingTransactionID: data.PreviousTxnID,
|
||||||
previousAffectingTransactionLedgerVersion: data.PreviousTxnLgrSeq
|
previousAffectingTransactionLedgerVersion: data.PreviousTxnLgrSeq,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,30 @@
|
|||||||
import _ from 'lodash'
|
import * as assert from "assert";
|
||||||
import * as assert from 'assert'
|
|
||||||
import * as utils from './utils'
|
import _ from "lodash";
|
||||||
import {txFlags} from '../../common'
|
|
||||||
import {removeUndefined} from '../../utils'
|
import { txFlags } from "../../common";
|
||||||
import parseAmount from './amount'
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import parseAmount from "./amount";
|
||||||
|
import * as utils from "./utils";
|
||||||
|
|
||||||
function isNoDirectRipple(tx) {
|
function isNoDirectRipple(tx) {
|
||||||
return (tx.Flags & txFlags.Payment.NoRippleDirect) !== 0
|
return (tx.Flags & txFlags.Payment.NoRippleDirect) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isQualityLimited(tx) {
|
function isQualityLimited(tx) {
|
||||||
return (tx.Flags & txFlags.Payment.LimitQuality) !== 0
|
return (tx.Flags & txFlags.Payment.LimitQuality) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeGenericCounterparty(amount, address) {
|
function removeGenericCounterparty(amount, address) {
|
||||||
return amount.counterparty === address
|
return amount.counterparty === address
|
||||||
? _.omit(amount, 'counterparty')
|
? _.omit(amount, "counterparty")
|
||||||
: amount
|
: amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Payment specification
|
// Payment specification
|
||||||
function parsePayment(tx: any): object {
|
function parsePayment(tx: any): object {
|
||||||
assert.ok(tx.TransactionType === 'Payment')
|
assert.ok(tx.TransactionType === "Payment");
|
||||||
|
|
||||||
const source = {
|
const source = {
|
||||||
address: tx.Account,
|
address: tx.Account,
|
||||||
@@ -29,17 +32,17 @@ function parsePayment(tx: any): object {
|
|||||||
parseAmount(tx.SendMax || tx.Amount),
|
parseAmount(tx.SendMax || tx.Amount),
|
||||||
tx.Account
|
tx.Account
|
||||||
),
|
),
|
||||||
tag: tx.SourceTag
|
tag: tx.SourceTag,
|
||||||
}
|
};
|
||||||
|
|
||||||
const destination: {
|
const destination: {
|
||||||
address: string
|
address: string;
|
||||||
tag: number | undefined
|
tag: number | undefined;
|
||||||
} = {
|
} = {
|
||||||
address: tx.Destination,
|
address: tx.Destination,
|
||||||
tag: tx.DestinationTag
|
tag: tx.DestinationTag,
|
||||||
// Notice that `amount` is omitted to prevent misinterpretation
|
// Notice that `amount` is omitted to prevent misinterpretation
|
||||||
}
|
};
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
source: removeUndefined(source),
|
source: removeUndefined(source),
|
||||||
@@ -49,8 +52,8 @@ function parsePayment(tx: any): object {
|
|||||||
paths: tx.Paths ? JSON.stringify(tx.Paths) : undefined,
|
paths: tx.Paths ? JSON.stringify(tx.Paths) : undefined,
|
||||||
allowPartialPayment: utils.isPartialPayment(tx) || undefined,
|
allowPartialPayment: utils.isPartialPayment(tx) || undefined,
|
||||||
noDirectRipple: isNoDirectRipple(tx) || undefined,
|
noDirectRipple: isNoDirectRipple(tx) || undefined,
|
||||||
limitQuality: isQualityLimited(tx) || undefined
|
limitQuality: isQualityLimited(tx) || undefined,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parsePayment
|
export default parsePayment;
|
||||||
|
|||||||
@@ -1,65 +1,69 @@
|
|||||||
import _ from 'lodash'
|
import * as assert from "assert";
|
||||||
import * as assert from 'assert'
|
|
||||||
import {constants} from '../../common'
|
import _ from "lodash";
|
||||||
const AccountFlags = constants.AccountFlags
|
|
||||||
import parseFields from './fields'
|
import { constants } from "../../common";
|
||||||
|
|
||||||
|
import parseFields from "./fields";
|
||||||
|
|
||||||
|
const AccountFlags = constants.AccountFlags;
|
||||||
|
|
||||||
function getAccountRootModifiedNode(tx: any) {
|
function getAccountRootModifiedNode(tx: any) {
|
||||||
const modifiedNodes = tx.meta.AffectedNodes.filter(
|
const modifiedNodes = tx.meta.AffectedNodes.filter(
|
||||||
(node) => node.ModifiedNode.LedgerEntryType === 'AccountRoot'
|
(node) => node.ModifiedNode.LedgerEntryType === "AccountRoot"
|
||||||
)
|
);
|
||||||
assert.ok(modifiedNodes.length === 1)
|
assert.ok(modifiedNodes.length === 1);
|
||||||
return modifiedNodes[0].ModifiedNode
|
return modifiedNodes[0].ModifiedNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseFlags(tx: any): any {
|
function parseFlags(tx: any): any {
|
||||||
const settings: any = {}
|
const settings: any = {};
|
||||||
if (tx.TransactionType !== 'AccountSet') {
|
if (tx.TransactionType !== "AccountSet") {
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
const node = getAccountRootModifiedNode(tx)
|
const node = getAccountRootModifiedNode(tx);
|
||||||
const oldFlags = _.get(node.PreviousFields, 'Flags')
|
const oldFlags = _.get(node.PreviousFields, "Flags");
|
||||||
const newFlags = _.get(node.FinalFields, 'Flags')
|
const newFlags = _.get(node.FinalFields, "Flags");
|
||||||
|
|
||||||
if (oldFlags != null && newFlags != null) {
|
if (oldFlags != null && newFlags != null) {
|
||||||
const changedFlags = oldFlags ^ newFlags
|
const changedFlags = oldFlags ^ newFlags;
|
||||||
const setFlags = newFlags & changedFlags
|
const setFlags = newFlags & changedFlags;
|
||||||
const clearedFlags = oldFlags & changedFlags
|
const clearedFlags = oldFlags & changedFlags;
|
||||||
Object.entries(AccountFlags).forEach(entry => {
|
Object.entries(AccountFlags).forEach((entry) => {
|
||||||
const [flagName, flagValue] = entry;
|
const [flagName, flagValue] = entry;
|
||||||
if (setFlags & flagValue) {
|
if (setFlags & flagValue) {
|
||||||
settings[flagName] = true
|
settings[flagName] = true;
|
||||||
} else if (clearedFlags & flagValue) {
|
} else if (clearedFlags & flagValue) {
|
||||||
settings[flagName] = false
|
settings[flagName] = false;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// enableTransactionIDTracking requires a special case because it
|
// enableTransactionIDTracking requires a special case because it
|
||||||
// does not affect the Flags field; instead it adds/removes a field called
|
// does not affect the Flags field; instead it adds/removes a field called
|
||||||
// "AccountTxnID" to/from the account root.
|
// "AccountTxnID" to/from the account root.
|
||||||
|
|
||||||
const oldField = _.get(node.PreviousFields, 'AccountTxnID')
|
const oldField = _.get(node.PreviousFields, "AccountTxnID");
|
||||||
const newField = _.get(node.FinalFields, 'AccountTxnID')
|
const newField = _.get(node.FinalFields, "AccountTxnID");
|
||||||
if (newField && !oldField) {
|
if (newField && !oldField) {
|
||||||
settings.enableTransactionIDTracking = true
|
settings.enableTransactionIDTracking = true;
|
||||||
} else if (oldField && !newField) {
|
} else if (oldField && !newField) {
|
||||||
settings.enableTransactionIDTracking = false
|
settings.enableTransactionIDTracking = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseSettings(tx: any) {
|
function parseSettings(tx: any) {
|
||||||
const txType = tx.TransactionType
|
const txType = tx.TransactionType;
|
||||||
assert.ok(
|
assert.ok(
|
||||||
txType === 'AccountSet' ||
|
txType === "AccountSet" ||
|
||||||
txType === 'SetRegularKey' ||
|
txType === "SetRegularKey" ||
|
||||||
txType === 'SignerListSet'
|
txType === "SignerListSet"
|
||||||
)
|
);
|
||||||
|
|
||||||
return Object.assign({}, parseFlags(tx), parseFields(tx))
|
return { ...parseFlags(tx), ...parseFields(tx) };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseSettings
|
export default parseSettings;
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
import {parseMemos} from './utils'
|
import { removeUndefined } from "../../utils";
|
||||||
|
|
||||||
|
import { parseMemos } from "./utils";
|
||||||
|
|
||||||
function parseTicketCreate(tx: any): object {
|
function parseTicketCreate(tx: any): object {
|
||||||
assert.ok(tx.TransactionType === 'TicketCreate')
|
assert.ok(tx.TransactionType === "TicketCreate");
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
memos: parseMemos(tx),
|
memos: parseMemos(tx),
|
||||||
ticketCount: tx.TicketCount
|
ticketCount: tx.TicketCount,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseTicketCreate
|
export default parseTicketCreate;
|
||||||
|
|||||||
@@ -1,59 +1,58 @@
|
|||||||
import {parseOutcome} from './utils'
|
import { removeUndefined } from "../../utils";
|
||||||
import {removeUndefined} from '../../utils'
|
|
||||||
|
|
||||||
import parseSettings from './settings'
|
import parseAccountDelete from "./account-delete";
|
||||||
import parseAccountDelete from './account-delete'
|
import parseAmendment from "./amendment"; // pseudo-transaction
|
||||||
import parseCheckCancel from './check-cancel'
|
import parseOrderCancellation from "./cancellation";
|
||||||
import parseCheckCash from './check-cash'
|
import parseCheckCancel from "./check-cancel";
|
||||||
import parseCheckCreate from './check-create'
|
import parseCheckCash from "./check-cash";
|
||||||
import parseDepositPreauth from './deposit-preauth'
|
import parseCheckCreate from "./check-create";
|
||||||
import parseEscrowCancellation from './escrow-cancellation'
|
import parseDepositPreauth from "./deposit-preauth";
|
||||||
import parseEscrowCreation from './escrow-creation'
|
import parseEscrowCancellation from "./escrow-cancellation";
|
||||||
import parseEscrowExecution from './escrow-execution'
|
import parseEscrowCreation from "./escrow-creation";
|
||||||
import parseOrderCancellation from './cancellation'
|
import parseEscrowExecution from "./escrow-execution";
|
||||||
import parseOrder from './order'
|
import parseFeeUpdate from "./fee-update"; // pseudo-transaction
|
||||||
import parsePayment from './payment'
|
import parseOrder from "./order";
|
||||||
import parsePaymentChannelClaim from './payment-channel-claim'
|
import parsePayment from "./payment";
|
||||||
import parsePaymentChannelCreate from './payment-channel-create'
|
import parsePaymentChannelClaim from "./payment-channel-claim";
|
||||||
import parsePaymentChannelFund from './payment-channel-fund'
|
import parsePaymentChannelCreate from "./payment-channel-create";
|
||||||
import parseTicketCreate from './ticket-create'
|
import parsePaymentChannelFund from "./payment-channel-fund";
|
||||||
import parseTrustline from './trustline'
|
import parseSettings from "./settings";
|
||||||
|
import parseTicketCreate from "./ticket-create";
|
||||||
import parseAmendment from './amendment' // pseudo-transaction
|
import parseTrustline from "./trustline";
|
||||||
import parseFeeUpdate from './fee-update' // pseudo-transaction
|
import { parseOutcome } from "./utils";
|
||||||
|
|
||||||
function parseTransactionType(type) {
|
function parseTransactionType(type) {
|
||||||
// Ordering matches https://developers.ripple.com/transaction-types.html
|
// Ordering matches https://developers.ripple.com/transaction-types.html
|
||||||
const mapping = {
|
const mapping = {
|
||||||
AccountSet: 'settings',
|
AccountSet: "settings",
|
||||||
AccountDelete: 'accountDelete',
|
AccountDelete: "accountDelete",
|
||||||
CheckCancel: 'checkCancel',
|
CheckCancel: "checkCancel",
|
||||||
CheckCash: 'checkCash',
|
CheckCash: "checkCash",
|
||||||
CheckCreate: 'checkCreate',
|
CheckCreate: "checkCreate",
|
||||||
DepositPreauth: 'depositPreauth',
|
DepositPreauth: "depositPreauth",
|
||||||
EscrowCancel: 'escrowCancellation',
|
EscrowCancel: "escrowCancellation",
|
||||||
EscrowCreate: 'escrowCreation',
|
EscrowCreate: "escrowCreation",
|
||||||
EscrowFinish: 'escrowExecution',
|
EscrowFinish: "escrowExecution",
|
||||||
OfferCancel: 'orderCancellation',
|
OfferCancel: "orderCancellation",
|
||||||
OfferCreate: 'order',
|
OfferCreate: "order",
|
||||||
Payment: 'payment',
|
Payment: "payment",
|
||||||
PaymentChannelClaim: 'paymentChannelClaim',
|
PaymentChannelClaim: "paymentChannelClaim",
|
||||||
PaymentChannelCreate: 'paymentChannelCreate',
|
PaymentChannelCreate: "paymentChannelCreate",
|
||||||
PaymentChannelFund: 'paymentChannelFund',
|
PaymentChannelFund: "paymentChannelFund",
|
||||||
SetRegularKey: 'settings',
|
SetRegularKey: "settings",
|
||||||
SignerListSet: 'settings',
|
SignerListSet: "settings",
|
||||||
TicketCreate: 'ticketCreate',
|
TicketCreate: "ticketCreate",
|
||||||
TrustSet: 'trustline',
|
TrustSet: "trustline",
|
||||||
|
|
||||||
EnableAmendment: 'amendment', // pseudo-transaction
|
EnableAmendment: "amendment", // pseudo-transaction
|
||||||
SetFee: 'feeUpdate' // pseudo-transaction
|
SetFee: "feeUpdate", // pseudo-transaction
|
||||||
}
|
};
|
||||||
return mapping[type] || null
|
return mapping[type] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// includeRawTransaction: undefined by default (getTransaction)
|
// includeRawTransaction: undefined by default (getTransaction)
|
||||||
function parseTransaction(tx: any, includeRawTransaction: boolean): any {
|
function parseTransaction(tx: any, includeRawTransaction: boolean): any {
|
||||||
const type = parseTransactionType(tx.TransactionType)
|
const type = parseTransactionType(tx.TransactionType);
|
||||||
const mapping = {
|
const mapping = {
|
||||||
settings: parseSettings,
|
settings: parseSettings,
|
||||||
accountDelete: parseAccountDelete,
|
accountDelete: parseAccountDelete,
|
||||||
@@ -74,31 +73,31 @@ function parseTransaction(tx: any, includeRawTransaction: boolean): any {
|
|||||||
trustline: parseTrustline,
|
trustline: parseTrustline,
|
||||||
|
|
||||||
amendment: parseAmendment, // pseudo-transaction
|
amendment: parseAmendment, // pseudo-transaction
|
||||||
feeUpdate: parseFeeUpdate // pseudo-transaction
|
feeUpdate: parseFeeUpdate, // pseudo-transaction
|
||||||
}
|
};
|
||||||
const parser: Function = mapping[type]
|
const parser: Function = mapping[type];
|
||||||
|
|
||||||
const specification = parser
|
const specification = parser
|
||||||
? parser(tx)
|
? parser(tx)
|
||||||
: {
|
: {
|
||||||
UNAVAILABLE: 'Unrecognized transaction type.',
|
UNAVAILABLE: "Unrecognized transaction type.",
|
||||||
SEE_RAW_TRANSACTION:
|
SEE_RAW_TRANSACTION:
|
||||||
'Since this type is unrecognized, `rawTransaction` is included in this response.'
|
"Since this type is unrecognized, `rawTransaction` is included in this response.",
|
||||||
}
|
};
|
||||||
if (!parser) {
|
if (!parser) {
|
||||||
includeRawTransaction = true
|
includeRawTransaction = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const outcome = parseOutcome(tx)
|
const outcome = parseOutcome(tx);
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
type: type,
|
type,
|
||||||
address: tx.Account,
|
address: tx.Account,
|
||||||
sequence: tx.Sequence,
|
sequence: tx.Sequence,
|
||||||
id: tx.hash,
|
id: tx.hash,
|
||||||
specification: removeUndefined(specification),
|
specification: removeUndefined(specification),
|
||||||
outcome: outcome ? removeUndefined(outcome) : undefined,
|
outcome: outcome ? removeUndefined(outcome) : undefined,
|
||||||
rawTransaction: includeRawTransaction ? JSON.stringify(tx) : undefined
|
rawTransaction: includeRawTransaction ? JSON.stringify(tx) : undefined,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseTransaction
|
export default parseTransaction;
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from "assert";
|
||||||
import {parseQuality, parseMemos} from './utils'
|
|
||||||
import {txFlags} from '../../common'
|
import { txFlags } from "../../common";
|
||||||
import {removeUndefined} from '../../utils'
|
import { removeUndefined } from "../../utils";
|
||||||
const flags = txFlags.TrustSet
|
|
||||||
|
import { parseQuality, parseMemos } from "./utils";
|
||||||
|
|
||||||
|
const flags = txFlags.TrustSet;
|
||||||
|
|
||||||
function parseFlag(flagsValue, trueValue, falseValue) {
|
function parseFlag(flagsValue, trueValue, falseValue) {
|
||||||
if (flagsValue & trueValue) {
|
if (flagsValue & trueValue) {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
if (flagsValue & falseValue) {
|
if (flagsValue & falseValue) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTrustline(tx: any): object {
|
function parseTrustline(tx: any): object {
|
||||||
assert.ok(tx.TransactionType === 'TrustSet')
|
assert.ok(tx.TransactionType === "TrustSet");
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
limit: tx.LimitAmount.value,
|
limit: tx.LimitAmount.value,
|
||||||
@@ -30,8 +33,8 @@ function parseTrustline(tx: any): object {
|
|||||||
flags.ClearNoRipple
|
flags.ClearNoRipple
|
||||||
),
|
),
|
||||||
frozen: parseFlag(tx.Flags, flags.SetFreeze, flags.ClearFreeze),
|
frozen: parseFlag(tx.Flags, flags.SetFreeze, flags.ClearFreeze),
|
||||||
authorized: parseFlag(tx.Flags, flags.SetAuth, 0)
|
authorized: parseFlag(tx.Flags, flags.SetAuth, 0),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parseTrustline
|
export default parseTrustline;
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
import transactionParser from 'ripple-lib-transactionparser'
|
import BigNumber from "bignumber.js";
|
||||||
import BigNumber from 'bignumber.js'
|
import transactionParser from "ripple-lib-transactionparser";
|
||||||
import parseAmount from './amount'
|
|
||||||
|
|
||||||
import {Amount, Memo} from '../../common/types/objects'
|
import { txFlags } from "../../common";
|
||||||
import {txFlags} from '../../common'
|
import { Amount, Memo } from "../../common/types/objects";
|
||||||
import {removeUndefined, dropsToXrp, rippleTimeToISOTime} from '../../utils'
|
import { removeUndefined, dropsToXrp, rippleTimeToISOTime } from "../../utils";
|
||||||
|
|
||||||
type OfferDescription = {
|
import parseAmount from "./amount";
|
||||||
direction: string,
|
|
||||||
quantity: any,
|
interface OfferDescription {
|
||||||
totalPrice: any,
|
direction: string;
|
||||||
sequence: number,
|
quantity: any;
|
||||||
status: string,
|
totalPrice: any;
|
||||||
makerExchangeRate: string
|
sequence: number;
|
||||||
|
status: string;
|
||||||
|
makerExchangeRate: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Orderbook = {
|
interface Orderbook {
|
||||||
[key: string]: OfferDescription[]
|
[key: string]: OfferDescription[];
|
||||||
}
|
}
|
||||||
|
|
||||||
type BalanceSheetItem = {
|
interface BalanceSheetItem {
|
||||||
counterparty: string,
|
counterparty: string;
|
||||||
currency: string,
|
currency: string;
|
||||||
value: string
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type BalanceSheet = {
|
interface BalanceSheet {
|
||||||
[key: string]: BalanceSheetItem[]
|
[key: string]: BalanceSheetItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function adjustQualityForXRP(
|
function adjustQualityForXRP(
|
||||||
@@ -36,77 +37,79 @@ function adjustQualityForXRP(
|
|||||||
) {
|
) {
|
||||||
// quality = takerPays.value/takerGets.value
|
// quality = takerPays.value/takerGets.value
|
||||||
// using drops (1e-6 XRP) for XRP values
|
// using drops (1e-6 XRP) for XRP values
|
||||||
const numeratorShift = takerPaysCurrency === 'XRP' ? -6 : 0
|
const numeratorShift = takerPaysCurrency === "XRP" ? -6 : 0;
|
||||||
const denominatorShift = takerGetsCurrency === 'XRP' ? -6 : 0
|
const denominatorShift = takerGetsCurrency === "XRP" ? -6 : 0;
|
||||||
const shift = numeratorShift - denominatorShift
|
const shift = numeratorShift - denominatorShift;
|
||||||
return shift === 0
|
return shift === 0
|
||||||
? quality
|
? quality
|
||||||
: new BigNumber(quality).shiftedBy(shift).toString()
|
: new BigNumber(quality).shiftedBy(shift).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseQuality(quality?: number | null): number | undefined {
|
function parseQuality(quality?: number | null): number | undefined {
|
||||||
if (typeof quality !== 'number') {
|
if (typeof quality !== "number") {
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
return new BigNumber(quality).shiftedBy(-9).toNumber()
|
return new BigNumber(quality).shiftedBy(-9).toNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTimestamp(rippleTime?: number | null): string | undefined {
|
function parseTimestamp(rippleTime?: number | null): string | undefined {
|
||||||
if (typeof rippleTime !== 'number') {
|
if (typeof rippleTime !== "number") {
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
return rippleTimeToISOTime(rippleTime)
|
return rippleTimeToISOTime(rippleTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeEmptyCounterparty(amount) {
|
function removeEmptyCounterparty(amount) {
|
||||||
if (amount.counterparty === '') {
|
if (amount.counterparty === "") {
|
||||||
delete amount.counterparty
|
delete amount.counterparty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeEmptyCounterpartyInBalanceChanges(balanceChanges: BalanceSheet) {
|
function removeEmptyCounterpartyInBalanceChanges(balanceChanges: BalanceSheet) {
|
||||||
Object.entries(balanceChanges).forEach(([_, changes]) => {
|
Object.entries(balanceChanges).forEach(([_, changes]) => {
|
||||||
changes.forEach(removeEmptyCounterparty)
|
changes.forEach(removeEmptyCounterparty);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeEmptyCounterpartyInOrderbookChanges(orderbookChanges: Orderbook) {
|
function removeEmptyCounterpartyInOrderbookChanges(
|
||||||
|
orderbookChanges: Orderbook
|
||||||
|
) {
|
||||||
Object.entries(orderbookChanges).forEach(([_, changes]) => {
|
Object.entries(orderbookChanges).forEach(([_, changes]) => {
|
||||||
changes.forEach((change) => {
|
changes.forEach((change) => {
|
||||||
Object.entries(change).forEach(removeEmptyCounterparty)
|
Object.entries(change).forEach(removeEmptyCounterparty);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPartialPayment(tx: any) {
|
function isPartialPayment(tx: any) {
|
||||||
return (tx.Flags & txFlags.Payment.PartialPayment) !== 0
|
return (tx.Flags & txFlags.Payment.PartialPayment) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDeliveredAmount(tx: any): Amount | void {
|
function parseDeliveredAmount(tx: any): Amount | void {
|
||||||
if (
|
if (
|
||||||
tx.TransactionType !== 'Payment' ||
|
tx.TransactionType !== "Payment" ||
|
||||||
tx.meta.TransactionResult !== 'tesSUCCESS'
|
tx.meta.TransactionResult !== "tesSUCCESS"
|
||||||
) {
|
) {
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.meta.delivered_amount && tx.meta.delivered_amount === 'unavailable') {
|
if (tx.meta.delivered_amount && tx.meta.delivered_amount === "unavailable") {
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parsable delivered_amount
|
// parsable delivered_amount
|
||||||
if (tx.meta.delivered_amount) {
|
if (tx.meta.delivered_amount) {
|
||||||
return parseAmount(tx.meta.delivered_amount)
|
return parseAmount(tx.meta.delivered_amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliveredAmount only present on partial payments
|
// DeliveredAmount only present on partial payments
|
||||||
if (tx.meta.DeliveredAmount) {
|
if (tx.meta.DeliveredAmount) {
|
||||||
return parseAmount(tx.meta.DeliveredAmount)
|
return parseAmount(tx.meta.DeliveredAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// no partial payment flag, use tx.Amount
|
// no partial payment flag, use tx.Amount
|
||||||
if (tx.Amount && !isPartialPayment(tx)) {
|
if (tx.Amount && !isPartialPayment(tx)) {
|
||||||
return parseAmount(tx.Amount)
|
return parseAmount(tx.Amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliveredAmount field was introduced at
|
// DeliveredAmount field was introduced at
|
||||||
@@ -116,52 +119,52 @@ function parseDeliveredAmount(tx: any): Amount | void {
|
|||||||
// transferred with a partial payment before
|
// transferred with a partial payment before
|
||||||
// that date must be derived from metadata.
|
// that date must be derived from metadata.
|
||||||
if (tx.Amount && tx.ledger_index > 4594094) {
|
if (tx.Amount && tx.ledger_index > 4594094) {
|
||||||
return parseAmount(tx.Amount)
|
return parseAmount(tx.Amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseOutcome(tx: any): any | undefined {
|
function parseOutcome(tx: any): any | undefined {
|
||||||
const metadata = tx.meta || tx.metaData
|
const metadata = tx.meta || tx.metaData;
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
const balanceChanges = transactionParser.parseBalanceChanges(metadata)
|
const balanceChanges = transactionParser.parseBalanceChanges(metadata);
|
||||||
const orderbookChanges = transactionParser.parseOrderbookChanges(metadata)
|
const orderbookChanges = transactionParser.parseOrderbookChanges(metadata);
|
||||||
const channelChanges = transactionParser.parseChannelChanges(metadata)
|
const channelChanges = transactionParser.parseChannelChanges(metadata);
|
||||||
|
|
||||||
removeEmptyCounterpartyInBalanceChanges(balanceChanges)
|
removeEmptyCounterpartyInBalanceChanges(balanceChanges);
|
||||||
removeEmptyCounterpartyInOrderbookChanges(orderbookChanges)
|
removeEmptyCounterpartyInOrderbookChanges(orderbookChanges);
|
||||||
|
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
result: tx.meta.TransactionResult,
|
result: tx.meta.TransactionResult,
|
||||||
timestamp: parseTimestamp(tx.date),
|
timestamp: parseTimestamp(tx.date),
|
||||||
fee: dropsToXrp(tx.Fee),
|
fee: dropsToXrp(tx.Fee),
|
||||||
balanceChanges: balanceChanges,
|
balanceChanges,
|
||||||
orderbookChanges: orderbookChanges,
|
orderbookChanges,
|
||||||
channelChanges: channelChanges,
|
channelChanges,
|
||||||
ledgerVersion: tx.ledger_index,
|
ledgerVersion: tx.ledger_index,
|
||||||
indexInLedger: tx.meta.TransactionIndex,
|
indexInLedger: tx.meta.TransactionIndex,
|
||||||
deliveredAmount: parseDeliveredAmount(tx)
|
deliveredAmount: parseDeliveredAmount(tx),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function hexToString(hex: string): string | undefined {
|
function hexToString(hex: string): string | undefined {
|
||||||
return hex ? Buffer.from(hex, 'hex').toString('utf-8') : undefined
|
return hex ? Buffer.from(hex, "hex").toString("utf-8") : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseMemos(tx: any): Array<Memo> | undefined {
|
function parseMemos(tx: any): Memo[] | undefined {
|
||||||
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
|
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
return tx.Memos.map((m) => {
|
return tx.Memos.map((m) => {
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
type: m.Memo.parsed_memo_type || hexToString(m.Memo.MemoType),
|
type: m.Memo.parsed_memo_type || hexToString(m.Memo.MemoType),
|
||||||
format: m.Memo.parsed_memo_format || hexToString(m.Memo.MemoFormat),
|
format: m.Memo.parsed_memo_format || hexToString(m.Memo.MemoFormat),
|
||||||
data: m.Memo.parsed_memo_data || hexToString(m.Memo.MemoData)
|
data: m.Memo.parsed_memo_data || hexToString(m.Memo.MemoData),
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -171,5 +174,5 @@ export {
|
|||||||
hexToString,
|
hexToString,
|
||||||
parseTimestamp,
|
parseTimestamp,
|
||||||
adjustQualityForXRP,
|
adjustQualityForXRP,
|
||||||
isPartialPayment
|
isPartialPayment,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -3,64 +3,64 @@ import {
|
|||||||
RippledAmount,
|
RippledAmount,
|
||||||
Adjustment,
|
Adjustment,
|
||||||
MaxAdjustment,
|
MaxAdjustment,
|
||||||
MinAdjustment
|
MinAdjustment,
|
||||||
} from '../common/types/objects'
|
} from "../common/types/objects";
|
||||||
|
|
||||||
// Amount where counterparty and value are optional
|
// Amount where counterparty and value are optional
|
||||||
export type LaxLaxAmount = {
|
export interface LaxLaxAmount {
|
||||||
currency: string
|
currency: string;
|
||||||
value?: string
|
value?: string;
|
||||||
issuer?: string
|
issuer?: string;
|
||||||
counterparty?: string
|
counterparty?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Path = {
|
export interface Path {
|
||||||
source: Adjustment | MaxAdjustment
|
source: Adjustment | MaxAdjustment;
|
||||||
destination: Adjustment | MinAdjustment
|
destination: Adjustment | MinAdjustment;
|
||||||
paths: string
|
paths: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetPaths = Array<Path>
|
export type GetPaths = Path[];
|
||||||
|
|
||||||
export type PathFind = {
|
export interface PathFind {
|
||||||
source: {
|
source: {
|
||||||
address: string
|
address: string;
|
||||||
amount?: Amount
|
amount?: Amount;
|
||||||
currencies?: Array<{currency: string; counterparty?: string}>
|
currencies?: Array<{ currency: string; counterparty?: string }>;
|
||||||
}
|
};
|
||||||
destination: {
|
destination: {
|
||||||
address: string
|
address: string;
|
||||||
amount: LaxLaxAmount
|
amount: LaxLaxAmount;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PathFindRequest = {
|
export interface PathFindRequest {
|
||||||
command: string
|
command: string;
|
||||||
source_account: string
|
source_account: string;
|
||||||
destination_amount: RippledAmount
|
destination_amount: RippledAmount;
|
||||||
destination_account: string
|
destination_account: string;
|
||||||
source_currencies?: {currency: string; issuer?: string}[]
|
source_currencies?: Array<{ currency: string; issuer?: string }>;
|
||||||
send_max?: RippledAmount
|
send_max?: RippledAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RippledPathsResponse = {
|
export interface RippledPathsResponse {
|
||||||
alternatives: Array<{
|
alternatives: Array<{
|
||||||
paths_computed: Array<
|
paths_computed: Array<
|
||||||
Array<{
|
Array<{
|
||||||
type: number
|
type: number;
|
||||||
type_hex: string
|
type_hex: string;
|
||||||
account?: string
|
account?: string;
|
||||||
issuer?: string
|
issuer?: string;
|
||||||
currency?: string
|
currency?: string;
|
||||||
}>
|
}>
|
||||||
>
|
>;
|
||||||
source_amount: RippledAmount
|
source_amount: RippledAmount;
|
||||||
}>
|
}>;
|
||||||
type: string
|
type: string;
|
||||||
destination_account: string
|
destination_account: string;
|
||||||
destination_amount: RippledAmount
|
destination_amount: RippledAmount;
|
||||||
destination_currencies?: Array<string>
|
destination_currencies?: string[];
|
||||||
source_account: string
|
source_account: string;
|
||||||
source_currencies?: Array<{currency: string}>
|
source_currencies?: Array<{ currency: string }>;
|
||||||
full_reply?: boolean
|
full_reply?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +1,90 @@
|
|||||||
import _ from 'lodash'
|
import BigNumber from "bignumber.js";
|
||||||
import BigNumber from 'bignumber.js'
|
import _ from "lodash";
|
||||||
import {getXRPBalance, renameCounterpartyToIssuer} from './utils'
|
|
||||||
import {
|
import type { Client } from "..";
|
||||||
validate,
|
import { Connection } from "../client";
|
||||||
errors
|
import { validate, errors } from "../common";
|
||||||
} from '../common'
|
import { RippledAmount, Amount } from "../common/types/objects";
|
||||||
import {toRippledAmount, xrpToDrops, dropsToXrp} from '../utils'
|
import { RipplePathFindRequest } from "../models/methods";
|
||||||
import {Connection} from '../client'
|
import { toRippledAmount, xrpToDrops, dropsToXrp } from "../utils";
|
||||||
import parsePathfind from './parse/pathfind'
|
|
||||||
import {RippledAmount, Amount} from '../common/types/objects'
|
import parsePathfind from "./parse/pathfind";
|
||||||
import {
|
import {
|
||||||
GetPaths,
|
GetPaths,
|
||||||
PathFind,
|
PathFind,
|
||||||
RippledPathsResponse,
|
RippledPathsResponse,
|
||||||
PathFindRequest
|
PathFindRequest,
|
||||||
} from './pathfind-types'
|
} from "./pathfind-types";
|
||||||
import {Client} from '..'
|
import { getXRPBalance, renameCounterpartyToIssuer } from "./utils";
|
||||||
import { RipplePathFindRequest } from '../models/methods'
|
|
||||||
const NotFoundError = errors.NotFoundError
|
const NotFoundError = errors.NotFoundError;
|
||||||
const ValidationError = errors.ValidationError
|
const ValidationError = errors.ValidationError;
|
||||||
|
|
||||||
function addParams(
|
function addParams(
|
||||||
request: PathFindRequest,
|
request: PathFindRequest,
|
||||||
result: RippledPathsResponse
|
result: RippledPathsResponse
|
||||||
): RippledPathsResponse {
|
): RippledPathsResponse {
|
||||||
return _.defaults(
|
return _.defaults(
|
||||||
Object.assign({}, result, {
|
{
|
||||||
|
...result,
|
||||||
source_account: request.source_account,
|
source_account: request.source_account,
|
||||||
source_currencies: request.source_currencies
|
source_currencies: request.source_currencies,
|
||||||
}),
|
},
|
||||||
{destination_amount: request.destination_amount}
|
{ destination_amount: request.destination_amount }
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestPathFind(
|
function requestPathFind(
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
pathfind: PathFind
|
pathfind: PathFind
|
||||||
): Promise<RippledPathsResponse> {
|
): Promise<RippledPathsResponse> {
|
||||||
const destinationAmount: Amount = Object.assign(
|
const destinationAmount: Amount = {
|
||||||
{
|
// This is converted back to drops by toRippledAmount()
|
||||||
// This is converted back to drops by toRippledAmount()
|
value:
|
||||||
value:
|
pathfind.destination.amount.currency === "XRP" ? dropsToXrp("-1") : "-1",
|
||||||
pathfind.destination.amount.currency === 'XRP' ? dropsToXrp('-1') : '-1'
|
...pathfind.destination.amount,
|
||||||
},
|
};
|
||||||
pathfind.destination.amount
|
|
||||||
)
|
|
||||||
const request: RipplePathFindRequest = {
|
const request: RipplePathFindRequest = {
|
||||||
command: 'ripple_path_find',
|
command: "ripple_path_find",
|
||||||
source_account: pathfind.source.address,
|
source_account: pathfind.source.address,
|
||||||
destination_account: pathfind.destination.address,
|
destination_account: pathfind.destination.address,
|
||||||
// @ts-ignore
|
// @ts-expect-error
|
||||||
destination_amount: destinationAmount
|
destination_amount: destinationAmount,
|
||||||
}
|
};
|
||||||
if (
|
if (
|
||||||
typeof request.destination_amount === 'object' &&
|
typeof request.destination_amount === "object" &&
|
||||||
!request.destination_amount.issuer
|
!request.destination_amount.issuer
|
||||||
) {
|
) {
|
||||||
// Convert blank issuer to sender's address
|
// Convert blank issuer to sender's address
|
||||||
// (Ripple convention for 'any issuer')
|
// (Ripple convention for 'any issuer')
|
||||||
// https://developers.ripple.com/payment.html#special-issuer-values-for-sendmax-and-amount
|
// https://developers.ripple.com/payment.html#special-issuer-values-for-sendmax-and-amount
|
||||||
request.destination_amount.issuer = request.destination_account
|
request.destination_amount.issuer = request.destination_account;
|
||||||
}
|
}
|
||||||
if (pathfind.source.currencies && pathfind.source.currencies.length > 0) {
|
if (pathfind.source.currencies && pathfind.source.currencies.length > 0) {
|
||||||
// @ts-ignore
|
// @ts-expect-error
|
||||||
request.source_currencies = pathfind.source.currencies.map((amount) =>
|
request.source_currencies = pathfind.source.currencies.map((amount) =>
|
||||||
renameCounterpartyToIssuer(amount)
|
renameCounterpartyToIssuer(amount)
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
if (pathfind.source.amount) {
|
if (pathfind.source.amount) {
|
||||||
if (pathfind.destination.amount.value != null) {
|
if (pathfind.destination.amount.value != null) {
|
||||||
throw new ValidationError(
|
throw new ValidationError(
|
||||||
'Cannot specify both source.amount' +
|
"Cannot specify both source.amount" +
|
||||||
' and destination.amount.value in getPaths'
|
" and destination.amount.value in getPaths"
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-expect-error
|
||||||
request.send_max = toRippledAmount(pathfind.source.amount)
|
request.send_max = toRippledAmount(pathfind.source.amount);
|
||||||
if (typeof request.send_max !== 'string' && !request.send_max.issuer) {
|
if (
|
||||||
request.send_max.issuer = pathfind.source.address
|
request.send_max != null &&
|
||||||
|
typeof request.send_max !== "string" &&
|
||||||
|
!request.send_max.issuer
|
||||||
|
) {
|
||||||
|
request.send_max.issuer = pathfind.source.address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-expect-error
|
||||||
return connection.request(request).then((paths) => addParams(request, paths))
|
return connection.request(request).then((paths) => addParams(request, paths));
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDirectXrpPath(
|
function addDirectXrpPath(
|
||||||
@@ -89,22 +92,22 @@ function addDirectXrpPath(
|
|||||||
xrpBalance: string
|
xrpBalance: string
|
||||||
): RippledPathsResponse {
|
): RippledPathsResponse {
|
||||||
// Add XRP "path" only if the source acct has enough XRP to make the payment
|
// Add XRP "path" only if the source acct has enough XRP to make the payment
|
||||||
const destinationAmount = paths.destination_amount
|
const destinationAmount = paths.destination_amount;
|
||||||
// @ts-ignore: destinationAmount can be a currency amount object! Fix!
|
// @ts-expect-error: destinationAmount can be a currency amount object! Fix!
|
||||||
if (new BigNumber(xrpBalance).isGreaterThanOrEqualTo(destinationAmount)) {
|
if (new BigNumber(xrpBalance).isGreaterThanOrEqualTo(destinationAmount)) {
|
||||||
paths.alternatives.unshift({
|
paths.alternatives.unshift({
|
||||||
paths_computed: [],
|
paths_computed: [],
|
||||||
source_amount: paths.destination_amount
|
source_amount: paths.destination_amount,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
return paths
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRippledIOUAmount(amount: RippledAmount) {
|
function isRippledIOUAmount(amount: RippledAmount) {
|
||||||
// rippled XRP amounts are specified as decimal strings
|
// rippled XRP amounts are specified as decimal strings
|
||||||
return (
|
return (
|
||||||
typeof amount === 'object' && amount.currency && amount.currency !== 'XRP'
|
typeof amount === "object" && amount.currency && amount.currency !== "XRP"
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function conditionallyAddDirectXRPPath(
|
function conditionallyAddDirectXRPPath(
|
||||||
@@ -114,13 +117,14 @@ function conditionallyAddDirectXRPPath(
|
|||||||
): Promise<RippledPathsResponse> {
|
): Promise<RippledPathsResponse> {
|
||||||
if (
|
if (
|
||||||
isRippledIOUAmount(paths.destination_amount) ||
|
isRippledIOUAmount(paths.destination_amount) ||
|
||||||
!paths.destination_currencies.includes('XRP')
|
(paths.destination_currencies &&
|
||||||
|
!paths.destination_currencies.includes("XRP"))
|
||||||
) {
|
) {
|
||||||
return Promise.resolve(paths)
|
return Promise.resolve(paths);
|
||||||
}
|
}
|
||||||
return getXRPBalance(client, address, undefined).then((xrpBalance) =>
|
return getXRPBalance(client, address, undefined).then((xrpBalance) =>
|
||||||
addDirectXrpPath(paths, xrpBalance)
|
addDirectXrpPath(paths, xrpBalance)
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterSourceFundsLowPaths(
|
function filterSourceFundsLowPaths(
|
||||||
@@ -129,74 +133,72 @@ function filterSourceFundsLowPaths(
|
|||||||
): RippledPathsResponse {
|
): RippledPathsResponse {
|
||||||
if (
|
if (
|
||||||
pathfind.source.amount &&
|
pathfind.source.amount &&
|
||||||
pathfind.destination.amount.value == null &&
|
paths.alternatives &&
|
||||||
paths.alternatives
|
pathfind.destination.amount.value == null
|
||||||
) {
|
) {
|
||||||
paths.alternatives = paths.alternatives.filter((alt) => {
|
paths.alternatives = paths.alternatives.filter((alt) => {
|
||||||
if (!alt.source_amount) {
|
if (!alt.source_amount) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
if (pathfind.source.amount === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const pathfindSourceAmountValue = new BigNumber(
|
const pathfindSourceAmountValue = new BigNumber(
|
||||||
pathfind.source.amount.currency === 'XRP'
|
pathfind.source.amount.currency === "XRP"
|
||||||
? xrpToDrops(pathfind.source.amount.value)
|
? xrpToDrops(pathfind.source.amount.value)
|
||||||
: pathfind.source.amount.value
|
: pathfind.source.amount.value
|
||||||
)
|
);
|
||||||
const altSourceAmountValue = new BigNumber(
|
const altSourceAmountValue = new BigNumber(
|
||||||
typeof alt.source_amount === 'string'
|
typeof alt.source_amount === "string"
|
||||||
? alt.source_amount
|
? alt.source_amount
|
||||||
: alt.source_amount.value
|
: alt.source_amount.value
|
||||||
)
|
);
|
||||||
return altSourceAmountValue.eq(pathfindSourceAmountValue)
|
return altSourceAmountValue.eq(pathfindSourceAmountValue);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
return paths
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatResponse(pathfind: PathFind, paths: RippledPathsResponse) {
|
function formatResponse(pathfind: PathFind, paths: RippledPathsResponse) {
|
||||||
if (paths.alternatives && paths.alternatives.length > 0) {
|
if (paths.alternatives && paths.alternatives.length > 0) {
|
||||||
return parsePathfind(paths)
|
return parsePathfind(paths);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
paths.destination_currencies != null &&
|
paths.destination_currencies != null &&
|
||||||
!paths.destination_currencies.includes(
|
!paths.destination_currencies.includes(pathfind.destination.amount.currency)
|
||||||
pathfind.destination.amount.currency
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
throw new NotFoundError(
|
throw new NotFoundError(
|
||||||
'No paths found. ' +
|
`${"No paths found. " + "The destination_account does not accept "}${
|
||||||
'The destination_account does not accept ' +
|
pathfind.destination.amount.currency
|
||||||
pathfind.destination.amount.currency +
|
}, they only accept: ${paths.destination_currencies.join(", ")}`
|
||||||
', they only accept: ' +
|
);
|
||||||
paths.destination_currencies.join(', ')
|
|
||||||
)
|
|
||||||
} else if (paths.source_currencies && paths.source_currencies.length > 0) {
|
} else if (paths.source_currencies && paths.source_currencies.length > 0) {
|
||||||
throw new NotFoundError(
|
throw new NotFoundError(
|
||||||
'No paths found. Please ensure' +
|
"No paths found. Please ensure" +
|
||||||
' that the source_account has sufficient funds to execute' +
|
" that the source_account has sufficient funds to execute" +
|
||||||
' the payment in one of the specified source_currencies. If it does' +
|
" the payment in one of the specified source_currencies. If it does" +
|
||||||
' there may be insufficient liquidity in the network to execute' +
|
" there may be insufficient liquidity in the network to execute" +
|
||||||
' this payment right now'
|
" this payment right now"
|
||||||
)
|
);
|
||||||
} else {
|
} else {
|
||||||
throw new NotFoundError(
|
throw new NotFoundError(
|
||||||
'No paths found.' +
|
"No paths found." +
|
||||||
' Please ensure that the source_account has sufficient funds to' +
|
" Please ensure that the source_account has sufficient funds to" +
|
||||||
' execute the payment. If it does there may be insufficient liquidity' +
|
" execute the payment. If it does there may be insufficient liquidity" +
|
||||||
' in the network to execute this payment right now'
|
" in the network to execute this payment right now"
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPaths(this: Client, pathfind: PathFind): Promise<GetPaths> {
|
function getPaths(this: Client, pathfind: PathFind): Promise<GetPaths> {
|
||||||
validate.getPaths({pathfind})
|
validate.getPaths({ pathfind });
|
||||||
|
|
||||||
const address = pathfind.source.address
|
const address = pathfind.source.address;
|
||||||
return requestPathFind(this.connection, pathfind)
|
return requestPathFind(this.connection, pathfind)
|
||||||
.then((paths) =>
|
.then((paths) => conditionallyAddDirectXRPPath(this, address, paths))
|
||||||
conditionallyAddDirectXRPPath(this, address, paths)
|
|
||||||
)
|
|
||||||
.then((paths) => filterSourceFundsLowPaths(pathfind, paths))
|
.then((paths) => filterSourceFundsLowPaths(pathfind, paths))
|
||||||
.then((paths) => formatResponse(pathfind, paths))
|
.then((paths) => formatResponse(pathfind, paths));
|
||||||
}
|
}
|
||||||
|
|
||||||
export default getPaths
|
export default getPaths;
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
import _ from 'lodash'
|
import _ from "lodash";
|
||||||
import {validate, ensureClassicAddress} from '../common'
|
|
||||||
import parseAccountTrustline from './parse/account-trustline'
|
|
||||||
import {Client} from '..'
|
|
||||||
import {FormattedTrustline} from '../common/types/objects/trustlines'
|
|
||||||
|
|
||||||
export type GetTrustlinesOptions = {
|
import type { Client } from "..";
|
||||||
counterparty?: string
|
import { validate, ensureClassicAddress } from "../common";
|
||||||
currency?: string
|
import { FormattedTrustline } from "../common/types/objects";
|
||||||
limit?: number
|
|
||||||
ledgerVersion?: number
|
import parseAccountTrustline from "./parse/account-trustline";
|
||||||
|
|
||||||
|
export interface GetTrustlinesOptions {
|
||||||
|
counterparty?: string;
|
||||||
|
currency?: string;
|
||||||
|
limit?: number;
|
||||||
|
ledgerVersion?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function currencyFilter(currency: string, trustline: FormattedTrustline) {
|
function currencyFilter(
|
||||||
return currency === null || trustline.specification.currency === currency
|
currency: string | null,
|
||||||
|
trustline: FormattedTrustline
|
||||||
|
) {
|
||||||
|
return currency === null || trustline.specification.currency === currency;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getTrustlines(
|
async function getTrustlines(
|
||||||
@@ -21,25 +26,26 @@ async function getTrustlines(
|
|||||||
options: GetTrustlinesOptions = {}
|
options: GetTrustlinesOptions = {}
|
||||||
): Promise<FormattedTrustline[]> {
|
): Promise<FormattedTrustline[]> {
|
||||||
// 1. Validate
|
// 1. Validate
|
||||||
validate.getTrustlines({address, options})
|
validate.getTrustlines({ address, options });
|
||||||
|
|
||||||
// Only support retrieving trustlines without a tag,
|
// Only support retrieving trustlines without a tag,
|
||||||
// since it does not make sense to filter trustlines
|
// since it does not make sense to filter trustlines
|
||||||
// by tag.
|
// by tag.
|
||||||
address = ensureClassicAddress(address)
|
address = ensureClassicAddress(address);
|
||||||
|
|
||||||
// 2. Make Request
|
// 2. Make Request
|
||||||
const responses = await this.requestAll({command: 'account_lines',
|
const responses = await this.requestAll({
|
||||||
|
command: "account_lines",
|
||||||
account: address,
|
account: address,
|
||||||
ledger_index: options.ledgerVersion ?? 'validated',
|
ledger_index: options.ledgerVersion ?? "validated",
|
||||||
limit: options.limit,
|
limit: options.limit,
|
||||||
peer: options.counterparty
|
peer: options.counterparty,
|
||||||
})
|
});
|
||||||
// 3. Return Formatted Response
|
// 3. Return Formatted Response
|
||||||
const trustlines = _.flatMap(responses, (response) => response.result.lines)
|
const trustlines = _.flatMap(responses, (response) => response.result.lines);
|
||||||
return trustlines.map(parseAccountTrustline).filter((trustline) => {
|
return trustlines.map(parseAccountTrustline).filter((trustline) => {
|
||||||
return currencyFilter(options.currency || null, trustline)
|
return currencyFilter(options.currency ?? null, trustline);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default getTrustlines
|
export default getTrustlines;
|
||||||
|
|||||||
@@ -1,23 +1,27 @@
|
|||||||
import _ from 'lodash'
|
import * as assert from "assert";
|
||||||
import * as assert from 'assert'
|
|
||||||
import * as common from '../common'
|
|
||||||
import {Connection} from '../client'
|
|
||||||
import {FormattedTransactionType} from '../transaction/types'
|
|
||||||
import {Issue} from '../common/types/objects'
|
|
||||||
import {Client} from '..'
|
|
||||||
import {AccountInfoRequest} from '../models/methods'
|
|
||||||
import {dropsToXrp} from '..'
|
|
||||||
|
|
||||||
export type RecursiveData = {
|
import _ from "lodash";
|
||||||
marker: string
|
|
||||||
results: Array<any>
|
import { Client, dropsToXrp } from "..";
|
||||||
|
import { Connection } from "../client";
|
||||||
|
import * as common from "../common";
|
||||||
|
import { Issue } from "../common/types/objects";
|
||||||
|
import { AccountInfoRequest } from "../models/methods";
|
||||||
|
import { FormattedTransactionType } from "../transaction/types";
|
||||||
|
|
||||||
|
export interface RecursiveData {
|
||||||
|
marker: string;
|
||||||
|
results: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Getter = (marker?: string, limit?: number) => Promise<RecursiveData>
|
export type Getter = (
|
||||||
|
marker?: string,
|
||||||
|
limit?: number
|
||||||
|
) => Promise<RecursiveData>;
|
||||||
|
|
||||||
function clamp(value: number, min: number, max: number): number {
|
function clamp(value: number, min: number, max: number): number {
|
||||||
assert.ok(min <= max, 'Illegal clamp bounds')
|
assert.ok(min <= max, "Illegal clamp bounds");
|
||||||
return Math.min(Math.max(value, min), max)
|
return Math.min(Math.max(value, min), max);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getXRPBalance(
|
async function getXRPBalance(
|
||||||
@@ -26,13 +30,12 @@ async function getXRPBalance(
|
|||||||
ledgerVersion?: number
|
ledgerVersion?: number
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const request: AccountInfoRequest = {
|
const request: AccountInfoRequest = {
|
||||||
command: 'account_info',
|
command: "account_info",
|
||||||
account: address,
|
account: address,
|
||||||
ledger_index: ledgerVersion
|
ledger_index: ledgerVersion,
|
||||||
}
|
};
|
||||||
const data = await client
|
const data = await client.request(request);
|
||||||
.request(request)
|
return dropsToXrp(data.result.account_data.Balance);
|
||||||
return dropsToXrp(data.result.account_data.Balance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the marker is omitted from a response, you have reached the end
|
// If the marker is omitted from a response, you have reached the end
|
||||||
@@ -40,64 +43,71 @@ async function getRecursiveRecur(
|
|||||||
getter: Getter,
|
getter: Getter,
|
||||||
marker: string | undefined,
|
marker: string | undefined,
|
||||||
limit: number
|
limit: number
|
||||||
): Promise<Array<any>> {
|
): Promise<any[]> {
|
||||||
const data = await getter(marker, limit)
|
const data = await getter(marker, limit);
|
||||||
const remaining = limit - data.results.length
|
const remaining = limit - data.results.length;
|
||||||
if (remaining > 0 && data.marker != null) {
|
if (remaining > 0 && data.marker != null) {
|
||||||
return getRecursiveRecur(getter, data.marker, remaining).then((results) => data.results.concat(results)
|
return getRecursiveRecur(getter, data.marker, remaining).then((results) =>
|
||||||
)
|
data.results.concat(results)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return data.results.slice(0, limit)
|
return data.results.slice(0, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRecursive(getter: Getter, limit?: number): Promise<Array<any>> {
|
function getRecursive(getter: Getter, limit?: number): Promise<any[]> {
|
||||||
return getRecursiveRecur(getter, undefined, limit || Infinity)
|
return getRecursiveRecur(getter, undefined, limit || Infinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renameCounterpartyToIssuer<T>(
|
function renameCounterpartyToIssuer<T>(
|
||||||
obj: T & {counterparty?: string; issuer?: string}
|
obj: T & { counterparty?: string; issuer?: string }
|
||||||
): T & {issuer?: string} {
|
): T & { issuer?: string } {
|
||||||
const issuer =
|
const issuer =
|
||||||
obj.counterparty != null
|
obj.counterparty != null
|
||||||
? obj.counterparty
|
? obj.counterparty
|
||||||
: obj.issuer != null
|
: obj.issuer != null
|
||||||
? obj.issuer
|
? obj.issuer
|
||||||
: undefined
|
: undefined;
|
||||||
const withIssuer = Object.assign({}, obj, {issuer})
|
const withIssuer = { ...obj, issuer };
|
||||||
delete withIssuer.counterparty
|
delete withIssuer.counterparty;
|
||||||
return withIssuer
|
return withIssuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RequestBookOffersArgs = {taker_gets: Issue; taker_pays: Issue}
|
export interface RequestBookOffersArgs {
|
||||||
|
taker_gets: Issue;
|
||||||
|
taker_pays: Issue;
|
||||||
|
}
|
||||||
|
|
||||||
function renameCounterpartyToIssuerInOrder(order: RequestBookOffersArgs) {
|
function renameCounterpartyToIssuerInOrder(order: RequestBookOffersArgs) {
|
||||||
const taker_gets = renameCounterpartyToIssuer(order.taker_gets)
|
const taker_gets = renameCounterpartyToIssuer(order.taker_gets);
|
||||||
const taker_pays = renameCounterpartyToIssuer(order.taker_pays)
|
const taker_pays = renameCounterpartyToIssuer(order.taker_pays);
|
||||||
const changes = {taker_gets, taker_pays}
|
const changes = { taker_gets, taker_pays };
|
||||||
return Object.assign({}, order, _.omitBy(changes, value => value == null))
|
return { ...order, ..._.omitBy(changes, (value) => value == null) };
|
||||||
}
|
}
|
||||||
|
|
||||||
function signum(num) {
|
function signum(num) {
|
||||||
return num === 0 ? 0 : num > 0 ? 1 : -1
|
return num === 0 ? 0 : num > 0 ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Order two rippled transactions based on their ledger_index.
|
* Order two rippled transactions based on their ledger_index.
|
||||||
* If two transactions took place in the same ledger, sort
|
* If two transactions took place in the same ledger, sort
|
||||||
* them based on TransactionIndex
|
* them based on TransactionIndex
|
||||||
* See: https://developers.ripple.com/transaction-metadata.html
|
* See: https://developers.ripple.com/transaction-metadata.html.
|
||||||
|
*
|
||||||
|
* @param first
|
||||||
|
* @param second
|
||||||
*/
|
*/
|
||||||
function compareTransactions(
|
function compareTransactions(
|
||||||
first: FormattedTransactionType,
|
first: FormattedTransactionType,
|
||||||
second: FormattedTransactionType
|
second: FormattedTransactionType
|
||||||
): number {
|
): number {
|
||||||
if (!first.outcome || !second.outcome) {
|
if (!first.outcome || !second.outcome) {
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
if (first.outcome.ledgerVersion === second.outcome.ledgerVersion) {
|
if (first.outcome.ledgerVersion === second.outcome.ledgerVersion) {
|
||||||
return signum(first.outcome.indexInLedger - second.outcome.indexInLedger)
|
return signum(first.outcome.indexInLedger - second.outcome.indexInLedger);
|
||||||
}
|
}
|
||||||
return first.outcome.ledgerVersion < second.outcome.ledgerVersion ? -1 : 1
|
return first.outcome.ledgerVersion < second.outcome.ledgerVersion ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function isPendingLedgerVersion(
|
async function isPendingLedgerVersion(
|
||||||
@@ -105,27 +115,30 @@ async function isPendingLedgerVersion(
|
|||||||
maxLedgerVersion?: number
|
maxLedgerVersion?: number
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const response = await client.request({
|
const response = await client.request({
|
||||||
command: 'ledger',
|
command: "ledger",
|
||||||
ledger_index: 'validated'
|
ledger_index: "validated",
|
||||||
})
|
});
|
||||||
const ledgerVersion = response.result.ledger_index
|
const ledgerVersion = response.result.ledger_index;
|
||||||
return ledgerVersion < (maxLedgerVersion || 0)
|
return ledgerVersion < (maxLedgerVersion || 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ensureLedgerVersion(this: Client, options: any): Promise<object> {
|
async function ensureLedgerVersion(
|
||||||
|
this: Client,
|
||||||
|
options: any
|
||||||
|
): Promise<object> {
|
||||||
if (
|
if (
|
||||||
Boolean(options) &&
|
Boolean(options) &&
|
||||||
options.ledgerVersion != null &&
|
options.ledgerVersion != null &&
|
||||||
options.ledgerVersion !== null
|
options.ledgerVersion !== null
|
||||||
) {
|
) {
|
||||||
return Promise.resolve(options)
|
return Promise.resolve(options);
|
||||||
}
|
}
|
||||||
const response = await this.request({
|
const response = await this.request({
|
||||||
command: 'ledger',
|
command: "ledger",
|
||||||
ledger_index: 'validated'
|
ledger_index: "validated",
|
||||||
})
|
});
|
||||||
const ledgerVersion = response.result.ledger_index
|
const ledgerVersion = response.result.ledger_index;
|
||||||
return Object.assign({}, options, { ledgerVersion })
|
return { ...options, ledgerVersion };
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -138,5 +151,5 @@ export {
|
|||||||
isPendingLedgerVersion,
|
isPendingLedgerVersion,
|
||||||
clamp,
|
clamp,
|
||||||
common,
|
common,
|
||||||
Connection
|
Connection,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,23 +1,29 @@
|
|||||||
export type LedgerIndex = number | ('validated' | 'closed' | 'current')
|
export type LedgerIndex = number | ("validated" | "closed" | "current");
|
||||||
|
|
||||||
export type AccountObjectType = 'check' | 'escrow' | 'offer' | 'payment_channel' | 'signer_list' | 'state'
|
export type AccountObjectType =
|
||||||
|
| "check"
|
||||||
|
| "escrow"
|
||||||
|
| "offer"
|
||||||
|
| "payment_channel"
|
||||||
|
| "signer_list"
|
||||||
|
| "state";
|
||||||
|
|
||||||
export interface XRP {
|
export interface XRP {
|
||||||
currency: "XRP"
|
currency: "XRP";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IssuedCurrency {
|
export interface IssuedCurrency {
|
||||||
currency: string
|
currency: string;
|
||||||
issuer: string
|
issuer: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Currency = IssuedCurrency | XRP
|
export type Currency = IssuedCurrency | XRP;
|
||||||
|
|
||||||
export interface IssuedCurrencyAmount extends IssuedCurrency {
|
export interface IssuedCurrencyAmount extends IssuedCurrency {
|
||||||
value: string
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Amount = IssuedCurrencyAmount | string
|
export type Amount = IssuedCurrencyAmount | string;
|
||||||
|
|
||||||
export interface Signer {
|
export interface Signer {
|
||||||
Account: string;
|
Account: string;
|
||||||
@@ -31,17 +37,25 @@ export interface Memo {
|
|||||||
MemoFormat?: string;
|
MemoFormat?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StreamType = "consensus" | "ledger" | "manifests" | "peer_status" | "transactions" | "transactions_proposed" | "server" | "validations"
|
export type StreamType =
|
||||||
|
| "consensus"
|
||||||
|
| "ledger"
|
||||||
|
| "manifests"
|
||||||
|
| "peer_status"
|
||||||
|
| "transactions"
|
||||||
|
| "transactions_proposed"
|
||||||
|
| "server"
|
||||||
|
| "validations";
|
||||||
|
|
||||||
interface PathStep {
|
interface PathStep {
|
||||||
account?: string
|
account?: string;
|
||||||
currency?: string
|
currency?: string;
|
||||||
issuer?: string
|
issuer?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Path = PathStep[]
|
export type Path = PathStep[];
|
||||||
|
|
||||||
export interface SignerEntry {
|
export interface SignerEntry {
|
||||||
Account: string;
|
Account: string;
|
||||||
SignerWeight: number;
|
SignerWeight: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
import { Amount } from ".";
|
import { Amount } from ".";
|
||||||
|
|
||||||
interface CreatedNode {
|
interface CreatedNode {
|
||||||
CreatedNode: {
|
CreatedNode: {
|
||||||
LedgerEntryType: string
|
LedgerEntryType: string;
|
||||||
LedgerIndex: string
|
LedgerIndex: string;
|
||||||
NewFields: {[field: string]: any}
|
NewFields: { [field: string]: any };
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ModifiedNode {
|
interface ModifiedNode {
|
||||||
ModifiedNode: {
|
ModifiedNode: {
|
||||||
LedgerEntryType: string
|
LedgerEntryType: string;
|
||||||
LedgerIndex: string
|
LedgerIndex: string;
|
||||||
FinalFields: {[field: string]: any}
|
FinalFields: { [field: string]: any };
|
||||||
PreviousFields: {[field: string]: any}
|
PreviousFields: { [field: string]: any };
|
||||||
PreviousTxnID?: string
|
PreviousTxnID?: string;
|
||||||
PreviouTxnLgrSeq?: number
|
PreviouTxnLgrSeq?: number;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DeletedNode {
|
interface DeletedNode {
|
||||||
DeletedNode: {
|
DeletedNode: {
|
||||||
LedgerEntryType: string
|
LedgerEntryType: string;
|
||||||
LedgerIndex: string
|
LedgerIndex: string;
|
||||||
FinalFields: {[field: string]: any}
|
FinalFields: { [field: string]: any };
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type Node = CreatedNode | ModifiedNode | DeletedNode
|
type Node = CreatedNode | ModifiedNode | DeletedNode;
|
||||||
|
|
||||||
export default interface Metadata {
|
export default interface Metadata {
|
||||||
AffectedNodes: Node[]
|
AffectedNodes: Node[];
|
||||||
DeliveredAmount?: Amount
|
DeliveredAmount?: Amount;
|
||||||
delivered_amount?: Amount
|
delivered_amount?: Amount;
|
||||||
TransactionIndex: number
|
TransactionIndex: number;
|
||||||
TransactionResult: string
|
TransactionResult: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
import { Amount } from ".";
|
import { Amount } from ".";
|
||||||
|
|
||||||
interface CreatedNode {
|
interface CreatedNode {
|
||||||
CreatedNode: {
|
CreatedNode: {
|
||||||
LedgerEntryType: string
|
LedgerEntryType: string;
|
||||||
LedgerIndex: string
|
LedgerIndex: string;
|
||||||
NewFields: {[field: string]: any}
|
NewFields: { [field: string]: any };
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ModifiedNode {
|
interface ModifiedNode {
|
||||||
ModifiedNode: {
|
ModifiedNode: {
|
||||||
LedgerEntryType: string
|
LedgerEntryType: string;
|
||||||
LedgerIndex: string
|
LedgerIndex: string;
|
||||||
FinalFields: {[field: string]: any}
|
FinalFields: { [field: string]: any };
|
||||||
PreviousFields: {[field: string]: any}
|
PreviousFields: { [field: string]: any };
|
||||||
PreviousTxnID?: string
|
PreviousTxnID?: string;
|
||||||
PreviouTxnLgrSeq?: number
|
PreviouTxnLgrSeq?: number;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DeletedNode {
|
interface DeletedNode {
|
||||||
DeletedNode: {
|
DeletedNode: {
|
||||||
LedgerEntryType: string
|
LedgerEntryType: string;
|
||||||
LedgerIndex: string
|
LedgerIndex: string;
|
||||||
FinalFields: {[field: string]: any}
|
FinalFields: { [field: string]: any };
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type Node = CreatedNode | ModifiedNode | DeletedNode
|
type Node = CreatedNode | ModifiedNode | DeletedNode;
|
||||||
|
|
||||||
export interface TransactionMetadata {
|
export interface TransactionMetadata {
|
||||||
AffectedNodes: Node[]
|
AffectedNodes: Node[];
|
||||||
DeliveredAmount?: Amount
|
DeliveredAmount?: Amount;
|
||||||
delivered_amount?: Amount
|
delivered_amount?: Amount;
|
||||||
TransactionIndex: number
|
TransactionIndex: number;
|
||||||
TransactionResult: string
|
TransactionResult: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { BaseLedgerEntry } from "./baseLedgerEntry";
|
import { BaseLedgerEntry } from "./baseLedgerEntry";
|
||||||
|
|
||||||
export interface AccountRoot extends BaseLedgerEntry{
|
export interface AccountRoot extends BaseLedgerEntry {
|
||||||
LedgerEntryType: 'AccountRoot'
|
LedgerEntryType: "AccountRoot";
|
||||||
Account: string
|
Account: string;
|
||||||
Balance: string
|
Balance: string;
|
||||||
Flags: number
|
Flags: number;
|
||||||
OwnerCount: number
|
OwnerCount: number;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
Sequence: number
|
Sequence: number;
|
||||||
AccountTxnID?: string
|
AccountTxnID?: string;
|
||||||
Domain?: string
|
Domain?: string;
|
||||||
EmailHash?: string
|
EmailHash?: string;
|
||||||
MessageKey?: string
|
MessageKey?: string;
|
||||||
RegularKey?: string
|
RegularKey?: string;
|
||||||
TicketCount?: number
|
TicketCount?: number;
|
||||||
TickSize?: number
|
TickSize?: number;
|
||||||
TransferRate?: number
|
TransferRate?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import { BaseLedgerEntry } from "./baseLedgerEntry";
|
|||||||
|
|
||||||
interface Majority {
|
interface Majority {
|
||||||
Majority: {
|
Majority: {
|
||||||
Amendment: string
|
Amendment: string;
|
||||||
CloseTime: number
|
CloseTime: number;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Amendments extends BaseLedgerEntry {
|
export interface Amendments extends BaseLedgerEntry {
|
||||||
LedgerEntryType: 'Amendments'
|
LedgerEntryType: "Amendments";
|
||||||
Amendments?: string[]
|
Amendments?: string[];
|
||||||
Majorities?: Majority[]
|
Majorities?: Majority[];
|
||||||
Flags: 0
|
Flags: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export interface BaseLedgerEntry {
|
export interface BaseLedgerEntry {
|
||||||
index: string
|
index: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
import { Amount } from "../common";
|
import { Amount } from "../common";
|
||||||
|
|
||||||
import { BaseLedgerEntry } from "./baseLedgerEntry";
|
import { BaseLedgerEntry } from "./baseLedgerEntry";
|
||||||
|
|
||||||
export interface Check extends BaseLedgerEntry {
|
export interface Check extends BaseLedgerEntry {
|
||||||
LedgerEntryType: 'Check'
|
LedgerEntryType: "Check";
|
||||||
Account: string
|
Account: string;
|
||||||
Destination: string
|
Destination: string;
|
||||||
Flags: 0
|
Flags: 0;
|
||||||
OwnerNode: string
|
OwnerNode: string;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
SendMax: Amount
|
SendMax: Amount;
|
||||||
Sequence: number
|
Sequence: number;
|
||||||
DestinationNode?: string
|
DestinationNode?: string;
|
||||||
DestinationTag?: number
|
DestinationTag?: number;
|
||||||
Expiration?: number
|
Expiration?: number;
|
||||||
InvoiceID?: string
|
InvoiceID?: string;
|
||||||
SourceTag?: number
|
SourceTag?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { BaseLedgerEntry } from "./baseLedgerEntry";
|
import { BaseLedgerEntry } from "./baseLedgerEntry";
|
||||||
|
|
||||||
export interface DepositPreauth extends BaseLedgerEntry {
|
export interface DepositPreauth extends BaseLedgerEntry {
|
||||||
LedgerEntryType: 'DepositPreauth'
|
LedgerEntryType: "DepositPreauth";
|
||||||
Account: string
|
Account: string;
|
||||||
Authorize: string
|
Authorize: string;
|
||||||
Flags: 0
|
Flags: 0;
|
||||||
OwnerNode: string
|
OwnerNode: string;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { BaseLedgerEntry } from "./baseLedgerEntry";
|
import { BaseLedgerEntry } from "./baseLedgerEntry";
|
||||||
|
|
||||||
export interface DirectoryNode extends BaseLedgerEntry {
|
export interface DirectoryNode extends BaseLedgerEntry {
|
||||||
LedgerEntryType: 'DirectoryNode'
|
LedgerEntryType: "DirectoryNode";
|
||||||
Flags: number
|
Flags: number;
|
||||||
RootIndex: string
|
RootIndex: string;
|
||||||
Indexes: string[]
|
Indexes: string[];
|
||||||
IndexNext?: number
|
IndexNext?: number;
|
||||||
IndexPrevious?: number
|
IndexPrevious?: number;
|
||||||
Owner?: string
|
Owner?: string;
|
||||||
TakerPaysCurrency?: string
|
TakerPaysCurrency?: string;
|
||||||
TakerPaysIssuer?: string
|
TakerPaysIssuer?: string;
|
||||||
TakerGetsCurrency?: string
|
TakerGetsCurrency?: string;
|
||||||
TakerGetsIssuer?: string
|
TakerGetsIssuer?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { BaseLedgerEntry } from "./baseLedgerEntry";
|
import { BaseLedgerEntry } from "./baseLedgerEntry";
|
||||||
|
|
||||||
export interface Escrow extends BaseLedgerEntry {
|
export interface Escrow extends BaseLedgerEntry {
|
||||||
LedgerEntryType: 'Escrow'
|
LedgerEntryType: "Escrow";
|
||||||
Account: string
|
Account: string;
|
||||||
Destination: string
|
Destination: string;
|
||||||
Amount: string
|
Amount: string;
|
||||||
Condition?: string
|
Condition?: string;
|
||||||
CancelAfter?: number
|
CancelAfter?: number;
|
||||||
FinishAfter?: number
|
FinishAfter?: number;
|
||||||
Flags: number
|
Flags: number;
|
||||||
SourceTag?: number
|
SourceTag?: number;
|
||||||
DestinationTag?: number
|
DestinationTag?: number;
|
||||||
OwnerNode: string
|
OwnerNode: string;
|
||||||
DestinationNode?: string
|
DestinationNode?: string;
|
||||||
PreviousTxnID: string
|
PreviousTxnID: string;
|
||||||
PreviousTxnLgrSeq: number
|
PreviousTxnLgrSeq: number;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user