mirror of
https://github.com/Xahau/xahau.js.git
synced 2026-01-24 08:35:20 +00:00
Compare commits
139 Commits
nn/webpack
...
nn/blitz
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e9c922e41 | ||
|
|
e71123ad9d | ||
|
|
248445acd9 | ||
|
|
403b0c402a | ||
|
|
0644e0467b | ||
|
|
578f35dd35 | ||
|
|
a1dce6b1e0 | ||
|
|
8df224232c | ||
|
|
c3e68cc83f | ||
|
|
02fd0ce323 | ||
|
|
5b9e3dbdc4 | ||
|
|
e65d686cc7 | ||
|
|
b77e2590b3 | ||
|
|
9e3654d7d6 | ||
|
|
edcdd3a0fc | ||
|
|
f5dee87ca7 | ||
|
|
b522e703b4 | ||
|
|
0be819cf37 | ||
|
|
afe06451ac | ||
|
|
da92bb7f1a | ||
|
|
0996dc13b7 | ||
|
|
b3a72588ea | ||
|
|
1747b31a02 | ||
|
|
b7c4b16a8d | ||
|
|
bfeb737ad7 | ||
|
|
cc0b5a4ac9 | ||
|
|
dcfc31a036 | ||
|
|
955e21717a | ||
|
|
5200682915 | ||
|
|
297dee9b8f | ||
|
|
5d67f14ea3 | ||
|
|
564001515d | ||
|
|
b5b2909fed | ||
|
|
2a93f85f41 | ||
|
|
dd068c2710 | ||
|
|
f2216446e5 | ||
|
|
98c9b9bc14 | ||
|
|
57a6586898 | ||
|
|
c5f47cbffc | ||
|
|
6dba1b142c | ||
|
|
d734d886c4 | ||
|
|
8e1ab6c32b | ||
|
|
dac8c27b49 | ||
|
|
6eec7b0b77 | ||
|
|
94a8c65200 | ||
|
|
6fac420d9f | ||
|
|
05e1d4d3c5 | ||
|
|
e53df109b0 | ||
|
|
dbb134839a | ||
|
|
13c52859eb | ||
|
|
eb0445817e | ||
|
|
10445cff01 | ||
|
|
3cbdbac4f9 | ||
|
|
fd78d1edcd | ||
|
|
603b7ae85c | ||
|
|
fcc8977623 | ||
|
|
b9b32eb3d2 | ||
|
|
1037e0da88 | ||
|
|
29c0b84ad5 | ||
|
|
4f1e1d653c | ||
|
|
fe919315d4 | ||
|
|
3f29e5781d | ||
|
|
0dc1e08350 | ||
|
|
148cac6f3f | ||
|
|
0d32071e0e | ||
|
|
e7e0ece78b | ||
|
|
dc6baf7f39 | ||
|
|
851b352f32 | ||
|
|
633032ddd8 | ||
|
|
33f83947f1 | ||
|
|
af7b187dc7 | ||
|
|
1115f17a3e | ||
|
|
ac66c2174a | ||
|
|
eb56eb181a | ||
|
|
c401f703c7 | ||
|
|
04dd65af38 | ||
|
|
949cc031ee | ||
|
|
c8a2a6690b | ||
|
|
a996fafe79 | ||
|
|
e200de3073 | ||
|
|
8c5bc22317 | ||
|
|
aa6cef520c | ||
|
|
2ca164311b | ||
|
|
3f365d8591 | ||
|
|
e0f4d99d86 | ||
|
|
62538a75b1 | ||
|
|
91cc9e0461 | ||
|
|
b53bc2bc97 | ||
|
|
75f0bb4617 | ||
|
|
6268b9ea26 | ||
|
|
43802f9e22 | ||
|
|
b8be6c2f1b | ||
|
|
759e075e54 | ||
|
|
8b95ee5fab | ||
|
|
12cfed5c17 | ||
|
|
09ef8595e7 | ||
|
|
f9fe5936b1 | ||
|
|
da9feffada | ||
|
|
8e52854773 | ||
|
|
5120b0fc83 | ||
|
|
52f1789ecd | ||
|
|
0b08de5956 | ||
|
|
59396c3f8f | ||
|
|
f49b9d4b0e | ||
|
|
478e147ae0 | ||
|
|
d324056203 | ||
|
|
db8f7c1bcb | ||
|
|
4469d1cbf8 | ||
|
|
05365a8690 | ||
|
|
f6b9878334 | ||
|
|
f68eb37565 | ||
|
|
f95ffee0b0 | ||
|
|
d5d996a92e | ||
|
|
2ff0dde91d | ||
|
|
bec487cf71 | ||
|
|
c1edab547a | ||
|
|
fef5f858fd | ||
|
|
72f34d9388 | ||
|
|
930d214107 | ||
|
|
57c4d8be39 | ||
|
|
73109295b4 | ||
|
|
6d08b9e12c | ||
|
|
293f09d409 | ||
|
|
f9bce29174 | ||
|
|
7fde5a2658 | ||
|
|
d438430100 | ||
|
|
c431e70900 | ||
|
|
51b4ff7a2c | ||
|
|
ec54841617 | ||
|
|
2166d8349e | ||
|
|
1ecd6a7e2a | ||
|
|
a0907472c9 | ||
|
|
57112c086c | ||
|
|
b7f39e7225 | ||
|
|
f16876014c | ||
|
|
68ac32fc06 | ||
|
|
0886af33fd | ||
|
|
6e4868e6c7 | ||
|
|
718b0ac5a5 |
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2012-2015 Ripple Labs Inc.
|
||||
Copyright (c) 2012-2021 Contributers to xrpl.js
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
||||
@@ -33,7 +33,7 @@ See also: [RippleAPI Beginners Guide](https://xrpl.org/get-started-with-rippleap
|
||||
|
||||
In an existing project (with `package.json`), install `xrpl.js`:
|
||||
```
|
||||
$ npm install xrpl
|
||||
$ npm install xrpl@beta
|
||||
```
|
||||
|
||||
Then see the [documentation](#documentation).
|
||||
@@ -46,7 +46,7 @@ If you want to use `xrpl.js` with React Native you will need to have some of the
|
||||
|
||||
```shell
|
||||
npm install react-native-crypto
|
||||
npm install xrpl
|
||||
npm install xrpl@beta
|
||||
# install peer deps
|
||||
npm install react-native-randombytes
|
||||
# install latest rn-nodeify
|
||||
|
||||
@@ -6,6 +6,7 @@ This table shows which versions of xrpl.js are currently supported with security
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ---------------------- |
|
||||
| 2.x | :white_check_mark: Yes |
|
||||
| 1.x | :white_check_mark: Yes |
|
||||
| 0.x | :x: No |
|
||||
|
||||
|
||||
18
circle.yml
18
circle.yml
@@ -1,18 +0,0 @@
|
||||
machine:
|
||||
node:
|
||||
version: 6.11.3
|
||||
hosts:
|
||||
testripple.circleci.com: 127.0.0.1
|
||||
dependencies:
|
||||
pre:
|
||||
- wget https://s3-us-west-2.amazonaws.com/ripple-debs/rippled_0.30.1-b11-1.deb
|
||||
- sudo dpkg -i rippled_0.30.1-b11-1.deb
|
||||
test:
|
||||
pre:
|
||||
- rippled -a --start --conf "$HOME/$CIRCLE_PROJECT_REPONAME/test/integration/rippled.cfg":
|
||||
background: true
|
||||
override:
|
||||
- scripts/ci.sh "$CIRCLE_NODE_INDEX" "$CIRCLE_NODE_TOTAL":
|
||||
parallel: true
|
||||
post:
|
||||
- killall /usr/bin/rippled
|
||||
23
package-lock.json
generated
23
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "xrpl",
|
||||
"version": "2.0.0-beta.0",
|
||||
"version": "2.0.0-beta.2",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "xrpl",
|
||||
"version": "2.0.0-beta.0",
|
||||
"version": "2.0.0-beta.2",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/lodash": "^4.14.136",
|
||||
@@ -19,7 +19,6 @@
|
||||
"ripple-address-codec": "^4.1.1",
|
||||
"ripple-binary-codec": "^1.1.3",
|
||||
"ripple-keypairs": "^1.0.3",
|
||||
"ripple-lib-transactionparser": "0.8.2",
|
||||
"ws": "^8.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -6974,15 +6973,6 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/ripple-lib-transactionparser": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.8.2.tgz",
|
||||
"integrity": "sha512-1teosQLjYHLyOQrKUQfYyMjDR3MAq/Ga+MJuLUfpBMypl4LZB4bEoMcmG99/+WVTEiZOezJmH9iCSvm/MyxD+g==",
|
||||
"dependencies": {
|
||||
"bignumber.js": "^9.0.0",
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
@@ -13859,15 +13849,6 @@
|
||||
"ripple-address-codec": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"ripple-lib-transactionparser": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.8.2.tgz",
|
||||
"integrity": "sha512-1teosQLjYHLyOQrKUQfYyMjDR3MAq/Ga+MJuLUfpBMypl4LZB4bEoMcmG99/+WVTEiZOezJmH9iCSvm/MyxD+g==",
|
||||
"requires": {
|
||||
"bignumber.js": "^9.0.0",
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
|
||||
18
package.json
18
package.json
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "xrpl",
|
||||
"version": "2.0.0-beta.0",
|
||||
"version": "2.0.0-beta.2",
|
||||
"license": "ISC",
|
||||
"description": "A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser",
|
||||
"files": [
|
||||
"dist/npm/*",
|
||||
"build/ripple-latest-min.js",
|
||||
"build/ripple-latest.js"
|
||||
"build/xrpl-latest-min.js",
|
||||
"build/xrpl-latest.js"
|
||||
],
|
||||
"main": "dist/npm/",
|
||||
"unpkg": "build/ripple-latest-min.js",
|
||||
"jsdelivr": "build/ripple-latest-min.js",
|
||||
"unpkg": "build/xrpl-latest-min.js",
|
||||
"jsdelivr": "build/xrpl-latest-min.js",
|
||||
"types": "dist/npm/index.d.ts",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
@@ -26,7 +26,6 @@
|
||||
"ripple-address-codec": "^4.1.1",
|
||||
"ripple-binary-codec": "^1.1.3",
|
||||
"ripple-keypairs": "^1.0.3",
|
||||
"ripple-lib-transactionparser": "0.8.2",
|
||||
"ws": "^8.2.2"
|
||||
},
|
||||
"resolutions": {
|
||||
@@ -80,14 +79,15 @@
|
||||
"build:snippets": "tsc --build ./snippets/tsconfig.json",
|
||||
"build:lib": "tsc --build tsconfig.build.json",
|
||||
"build:web": "webpack",
|
||||
"build:browserTests": "webpack --config ./test/webpack.config.js",
|
||||
"analyze": "run-s build:web --analyze",
|
||||
"watch": "run-s build:lib --watch",
|
||||
"clean": "rm -rf dist",
|
||||
"docgen": "typedoc ./src/index.ts",
|
||||
"prepublish": "run-s clean build",
|
||||
"prepublish": "npm run clean && npm run build",
|
||||
"test": "nyc mocha --config=test/.mocharc.json --exit",
|
||||
"test:integration": "TS_NODE_PROJECT=tsconfig.build.json nyc mocha ./test/integration/**/*.ts ./test/integration/*.ts",
|
||||
"test:browser": "TS_NODE_PROJECT=tsconfig.build.json nyc mocha ./test/browser/*.ts",
|
||||
"test:browser": "npm run build:browserTests && 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",
|
||||
"format": "prettier --write '{src,test}/**/*.ts'",
|
||||
"lint": "eslint . --ext .ts --max-warnings 0",
|
||||
@@ -99,7 +99,7 @@
|
||||
"prettier": "@xrplf/prettier-config",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/ripple/ripple-lib.git"
|
||||
"url": "git@github.com:XRPLF/xrpl.js.git"
|
||||
},
|
||||
"readmeFilename": "README.md",
|
||||
"engines": {
|
||||
|
||||
@@ -216,6 +216,7 @@ export class Connection extends EventEmitter {
|
||||
* @throws ConnectionError if there is a connection error, RippleError if there is already a WebSocket in existence.
|
||||
*/
|
||||
public async connect(): Promise<void> {
|
||||
console.log('CONNECTING IN CONNECTION.CONNECT')
|
||||
if (this.isConnected()) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
@@ -304,7 +305,7 @@ export class Connection extends EventEmitter {
|
||||
public async reconnect(): Promise<void> {
|
||||
// NOTE: We currently have a "reconnecting" event, but that only triggers
|
||||
// through an unexpected connection retry logic.
|
||||
// See: https://github.com/ripple/ripple-lib/pull/1101#issuecomment-565360423
|
||||
// See: https://github.com/XRPLF/xrpl.js/pull/1101#issuecomment-565360423
|
||||
this.emit('reconnect')
|
||||
await this.disconnect()
|
||||
await this.connect()
|
||||
@@ -325,6 +326,7 @@ export class Connection extends EventEmitter {
|
||||
if (!this.shouldBeConnected || this.ws == null) {
|
||||
throw new NotConnectedError()
|
||||
}
|
||||
|
||||
const [id, message, responsePromise] = this.requestManager.createRequest(
|
||||
request,
|
||||
timeout ?? this.config.timeout,
|
||||
|
||||
@@ -6,6 +6,8 @@ import { EventEmitter } from 'events'
|
||||
import { ValidationError, XrplError } from '../errors'
|
||||
import * as errors from '../errors'
|
||||
import {
|
||||
Request,
|
||||
Response,
|
||||
// account methods
|
||||
AccountChannelsRequest,
|
||||
AccountChannelsResponse,
|
||||
@@ -86,6 +88,7 @@ import { BaseRequest, BaseResponse } from '../models/methods/baseMethod'
|
||||
import autofill from '../sugar/autofill'
|
||||
import getBalances from '../sugar/balances'
|
||||
import getFee from '../sugar/fee'
|
||||
import getLedgerIndex from '../sugar/ledgerIndex'
|
||||
import getOrderbook from '../sugar/orderbook'
|
||||
import { submitTransaction, submitSignedTransaction } from '../sugar/submit'
|
||||
import { ensureClassicAddress } from '../sugar/utils'
|
||||
@@ -96,6 +99,10 @@ import {
|
||||
ConnectionUserOptions,
|
||||
INTENTIONAL_DISCONNECT_CODE,
|
||||
} from './connection'
|
||||
import {
|
||||
handlePartialPayment,
|
||||
handleStreamPartialPayment,
|
||||
} from './partialPayment'
|
||||
|
||||
export interface ClientOptions extends ConnectionUserOptions {
|
||||
feeCushion?: number
|
||||
@@ -175,6 +182,8 @@ class Client extends EventEmitter {
|
||||
// eslint-disable-next-line max-lines-per-function -- okay because we have to set up all the connection handlers
|
||||
public constructor(server: string, options: ClientOptions = {}) {
|
||||
super()
|
||||
console.log('CONSTRUCTING CLIENT')
|
||||
|
||||
if (typeof server !== 'string' || !/wss?(?:\+unix)?:\/\//u.exec(server)) {
|
||||
throw new ValidationError(
|
||||
'server URI must start with `wss://`, `ws://`, `wss+unix://`, or `ws+unix://`.',
|
||||
@@ -209,6 +218,7 @@ class Client extends EventEmitter {
|
||||
})
|
||||
|
||||
this.connection.on('transaction', (tx) => {
|
||||
handleStreamPartialPayment(tx)
|
||||
this.emit('transaction', tx)
|
||||
})
|
||||
|
||||
@@ -295,6 +305,9 @@ class Client extends EventEmitter {
|
||||
r: TransactionEntryRequest,
|
||||
): Promise<TransactionEntryResponse>
|
||||
public async request(r: TxRequest): Promise<TxResponse>
|
||||
public async request<R extends BaseRequest, T extends BaseResponse>(
|
||||
r: R,
|
||||
): Promise<T>
|
||||
/**
|
||||
* Makes a request to the client with the given command and
|
||||
* additional request body parameters.
|
||||
@@ -302,17 +315,21 @@ class Client extends EventEmitter {
|
||||
* @param req - Request to send to the server.
|
||||
* @returns The response from the server.
|
||||
*/
|
||||
public async request<R extends BaseRequest, T extends BaseResponse>(
|
||||
public async request<R extends Request, T extends Response>(
|
||||
req: R,
|
||||
): Promise<T> {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Necessary for overloading
|
||||
return this.connection.request({
|
||||
const response = (await this.connection.request({
|
||||
...req,
|
||||
account: req.account
|
||||
? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Must be string
|
||||
ensureClassicAddress(req.account as string)
|
||||
: undefined,
|
||||
}) as unknown as T
|
||||
})) as T
|
||||
|
||||
handlePartialPayment(req.command, response)
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
public async requestNextPage(
|
||||
@@ -357,7 +374,7 @@ class Client extends EventEmitter {
|
||||
}
|
||||
const nextPageRequest = { ...req, marker: resp.result.marker }
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Necessary for overloading
|
||||
return this.connection.request(nextPageRequest) as unknown as U
|
||||
return this.request(nextPageRequest) as unknown as U
|
||||
}
|
||||
|
||||
public on(
|
||||
@@ -392,6 +409,10 @@ class Client extends EventEmitter {
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- actually needs to be any here
|
||||
public on(eventName: string, listener: (...args: any[]) => void): this {
|
||||
// if (args[0]?.type === 'transaction') {
|
||||
// handlePartialPaymentStream(args[0])
|
||||
// }
|
||||
|
||||
return super.on(eventName, listener)
|
||||
}
|
||||
|
||||
@@ -481,6 +502,8 @@ class Client extends EventEmitter {
|
||||
* @returns A promise that resolves with a void value when a connection is established.
|
||||
*/
|
||||
public async connect(): Promise<void> {
|
||||
console.log('CONNECTING IN CLIENT.CONNECT')
|
||||
|
||||
return this.connection.connect()
|
||||
}
|
||||
|
||||
@@ -504,23 +527,22 @@ class Client extends EventEmitter {
|
||||
return this.connection.isConnected()
|
||||
}
|
||||
|
||||
// syntactic sugar
|
||||
|
||||
public autofill = autofill
|
||||
|
||||
public getFee = getFee
|
||||
|
||||
// @deprecated Use autofill instead
|
||||
public prepareTransaction = autofill
|
||||
|
||||
public submitTransaction = submitTransaction
|
||||
public getFee = getFee
|
||||
public getLedgerIndex = getLedgerIndex
|
||||
|
||||
public submitTransaction = submitTransaction
|
||||
public submitSignedTransaction = submitSignedTransaction
|
||||
|
||||
public getBalances = getBalances
|
||||
public getOrderbook = getOrderbook
|
||||
|
||||
public generateFaucetWallet = generateFaucetWallet
|
||||
|
||||
public errors = errors
|
||||
}
|
||||
|
||||
export { Client }
|
||||
|
||||
146
src/client/partialPayment.ts
Normal file
146
src/client/partialPayment.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { decode } from 'ripple-binary-codec'
|
||||
|
||||
import type {
|
||||
AccountTxResponse,
|
||||
Response,
|
||||
TransactionEntryResponse,
|
||||
TransactionStream,
|
||||
TxResponse,
|
||||
} from '..'
|
||||
import type { Amount } from '../models/common'
|
||||
import { PaymentTransactionFlags, Transaction } from '../models/transactions'
|
||||
import type TransactionMetadata from '../models/transactions/metadata'
|
||||
import { isFlagEnabled } from '../models/utils'
|
||||
|
||||
const WARN_PARTIAL_PAYMENT_CODE = 2001
|
||||
|
||||
function amountsEqual(amt1: Amount, amt2: Amount): boolean {
|
||||
if (typeof amt1 === 'string' && typeof amt2 === 'string') {
|
||||
return amt1 === amt2
|
||||
}
|
||||
|
||||
if (typeof amt1 === 'string' || typeof amt2 === 'string') {
|
||||
return false
|
||||
}
|
||||
|
||||
const aValue = new BigNumber(amt1.value)
|
||||
const bValue = new BigNumber(amt2.value)
|
||||
|
||||
return (
|
||||
amt1.currency === amt2.currency &&
|
||||
amt1.issuer === amt2.issuer &&
|
||||
aValue.isEqualTo(bValue)
|
||||
)
|
||||
}
|
||||
|
||||
function isPartialPayment(
|
||||
tx?: Transaction,
|
||||
metadata?: TransactionMetadata | string,
|
||||
): boolean {
|
||||
if (tx == null || metadata == null || tx.TransactionType !== 'Payment') {
|
||||
return false
|
||||
}
|
||||
|
||||
let meta = metadata
|
||||
if (typeof meta === 'string') {
|
||||
if (meta === 'unavailable') {
|
||||
return false
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- binary-codec typing */
|
||||
meta = decode(meta) as unknown as TransactionMetadata
|
||||
}
|
||||
|
||||
const tfPartial =
|
||||
typeof tx.Flags === 'number'
|
||||
? isFlagEnabled(tx.Flags, PaymentTransactionFlags.tfPartialPayment)
|
||||
: tx.Flags?.tfPartialPayment
|
||||
|
||||
if (!tfPartial) {
|
||||
return false
|
||||
}
|
||||
|
||||
const delivered = meta.delivered_amount
|
||||
const amount = tx.Amount
|
||||
|
||||
if (delivered === undefined) {
|
||||
return false
|
||||
}
|
||||
|
||||
return !amountsEqual(delivered, amount)
|
||||
}
|
||||
|
||||
function txHasPartialPayment(response: TxResponse): boolean {
|
||||
return isPartialPayment(response.result, response.result.meta)
|
||||
}
|
||||
|
||||
function txEntryHasPartialPayment(response: TransactionEntryResponse): boolean {
|
||||
return isPartialPayment(response.result.tx_json, response.result.metadata)
|
||||
}
|
||||
|
||||
function accountTxHasPartialPayment(response: AccountTxResponse): boolean {
|
||||
const { transactions } = response.result
|
||||
const foo = transactions.some((tx) => isPartialPayment(tx.tx, tx.meta))
|
||||
return foo
|
||||
}
|
||||
|
||||
function hasPartialPayment(command: string, response: Response): boolean {
|
||||
/* eslint-disable @typescript-eslint/consistent-type-assertions -- Request type is known at runtime from command */
|
||||
switch (command) {
|
||||
case 'tx':
|
||||
return txHasPartialPayment(response as TxResponse)
|
||||
case 'transaction_entry':
|
||||
return txEntryHasPartialPayment(response as TransactionEntryResponse)
|
||||
case 'account_tx':
|
||||
return accountTxHasPartialPayment(response as AccountTxResponse)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/consistent-type-assertions */
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a response for a partial payment.
|
||||
*
|
||||
* @param command - Command from the request, tells us what response to expect.
|
||||
* @param response - Response to check for a partial payment.
|
||||
*/
|
||||
export function handlePartialPayment(
|
||||
command: string,
|
||||
response: Response,
|
||||
): void {
|
||||
if (hasPartialPayment(command, response)) {
|
||||
const warnings = response.warnings ?? []
|
||||
|
||||
const warning = {
|
||||
id: WARN_PARTIAL_PAYMENT_CODE,
|
||||
message: 'This response contains a Partial Payment',
|
||||
}
|
||||
|
||||
warnings.push(warning)
|
||||
|
||||
response.warnings = warnings
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a transaction from a subscription stream for partial payment.
|
||||
*
|
||||
* @param stream - Stream Transaction to check for partial payment,.
|
||||
*/
|
||||
export function handleStreamPartialPayment(stream: TransactionStream): void {
|
||||
if (isPartialPayment(stream.transaction, stream.meta)) {
|
||||
const warnings = stream.warnings ?? []
|
||||
|
||||
const warning = {
|
||||
id: WARN_PARTIAL_PAYMENT_CODE,
|
||||
message: 'This response contains a Partial Payment',
|
||||
}
|
||||
|
||||
warnings.push(warning)
|
||||
|
||||
/* eslint-disable-next-line no-param-reassign -- Handles the case where there are no warnings */
|
||||
stream.warnings = warnings
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
import { ResponseFormatError, RippledError, TimeoutError } from '../errors'
|
||||
import {
|
||||
ResponseFormatError,
|
||||
RippledError,
|
||||
TimeoutError,
|
||||
XrplError,
|
||||
} from '../errors'
|
||||
import { Response } from '../models/methods'
|
||||
import { BaseRequest, ErrorResponse } from '../models/methods/baseMethod'
|
||||
|
||||
@@ -77,6 +82,7 @@ export default class RequestManager {
|
||||
public rejectAll(error: Error): void {
|
||||
this.promisesAwaitingResponse.forEach((_promise, id, _map) => {
|
||||
this.reject(id, error)
|
||||
this.deletePromise(id)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -88,13 +94,19 @@ export default class RequestManager {
|
||||
* @param request - Request to create.
|
||||
* @param timeout - Timeout length to catch hung responses.
|
||||
* @returns Request ID, new request form, and the promise for resolving the request.
|
||||
* @throws XrplError if request with the same ID is already pending.
|
||||
*/
|
||||
public createRequest<T extends BaseRequest>(
|
||||
request: T,
|
||||
timeout: number,
|
||||
): [string | number, string, Promise<Response>] {
|
||||
const newId = request.id ? request.id : this.nextId
|
||||
this.nextId += 1
|
||||
let newId: string | number
|
||||
if (request.id == null) {
|
||||
newId = this.nextId
|
||||
this.nextId += 1
|
||||
} else {
|
||||
newId = request.id
|
||||
}
|
||||
const newRequest = JSON.stringify({ ...request, id: newId })
|
||||
const timer = setTimeout(
|
||||
() => this.reject(newId, new TimeoutError()),
|
||||
@@ -106,6 +118,9 @@ export default class RequestManager {
|
||||
if (timer.unref) {
|
||||
timer.unref()
|
||||
}
|
||||
if (this.promisesAwaitingResponse.has(newId)) {
|
||||
throw new XrplError(`Response with id '${newId}' is already pending`)
|
||||
}
|
||||
const newPromise = new Promise<Response>(
|
||||
(resolve: (value: Response | PromiseLike<Response>) => void, reject) => {
|
||||
this.promisesAwaitingResponse.set(newId, { resolve, reject, timer })
|
||||
@@ -125,8 +140,7 @@ export default class RequestManager {
|
||||
public handleResponse(response: Partial<Response | ErrorResponse>): void {
|
||||
if (
|
||||
response.id == null ||
|
||||
!Number.isInteger(response.id) ||
|
||||
response.id < 0
|
||||
!(typeof response.id === 'string' || typeof response.id === 'number')
|
||||
) {
|
||||
throw new ResponseFormatError('valid id not found in response', response)
|
||||
}
|
||||
@@ -165,7 +179,6 @@ export default class RequestManager {
|
||||
* @param id - ID of the request.
|
||||
*/
|
||||
private deletePromise(id: string | number): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- Needs to delete promise after request has been fulfilled.
|
||||
delete this.promisesAwaitingResponse[id]
|
||||
this.promisesAwaitingResponse.delete(id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,10 @@ class XrplError extends Error {
|
||||
this.name = this.constructor.name
|
||||
this.message = message
|
||||
this.data = data
|
||||
Error.captureStackTrace(this, this.constructor)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- `captureStackTrace` can be null in browsers
|
||||
if (Error.captureStackTrace != null) {
|
||||
Error.captureStackTrace(this, this.constructor)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Transaction } from '../transactions'
|
||||
import TransactionMetadata from '../transactions/metadata'
|
||||
|
||||
import LedgerEntry from './ledgerEntry'
|
||||
|
||||
@@ -16,5 +17,5 @@ export default interface Ledger {
|
||||
parent_hash: string
|
||||
total_coins: string
|
||||
transaction_hash: string
|
||||
transactions?: Transaction[]
|
||||
transactions?: Array<Transaction & { metaData?: TransactionMetadata }>
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export interface AccountChannelsRequest extends BaseRequest {
|
||||
destination_account?: string
|
||||
ledger_hash?: string
|
||||
ledger_index?: LedgerIndex
|
||||
limit: number
|
||||
limit?: number
|
||||
marker?: unknown
|
||||
}
|
||||
|
||||
|
||||
@@ -31,5 +31,6 @@ export interface BookOffersResponse extends BaseResponse {
|
||||
ledger_index?: number
|
||||
ledger_hash?: string
|
||||
offers: BookOffer[]
|
||||
validated?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ export interface GatewayBalancesRequest extends BaseRequest {
|
||||
command: 'gateway_balances'
|
||||
account: string
|
||||
strict?: boolean
|
||||
hotwallet: string | string[]
|
||||
hotwallet?: string | string[]
|
||||
ledger_hash?: string
|
||||
ledger_index?: LedgerIndex
|
||||
}
|
||||
|
||||
@@ -26,5 +26,6 @@ export interface LedgerDataResponse extends BaseResponse {
|
||||
ledger_hash: string
|
||||
state: State[]
|
||||
marker?: unknown
|
||||
validated?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,8 +65,9 @@ export interface LedgerEntryRequest extends BaseRequest {
|
||||
export interface LedgerEntryResponse extends BaseResponse {
|
||||
result: {
|
||||
index: string
|
||||
ledger_index: number
|
||||
ledger_current_index: number
|
||||
node?: LedgerEntry
|
||||
node_binary?: string
|
||||
validated?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,5 +28,11 @@ export interface RipplePathFindResponse extends BaseResponse {
|
||||
alternatives: PathOption[]
|
||||
destination_account: string
|
||||
destination_currencies: string[]
|
||||
destination_amount: Amount
|
||||
full_reply?: boolean
|
||||
id?: number | string
|
||||
ledger_current_index?: number
|
||||
source_account: string
|
||||
validated: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface SubmitResponse extends BaseResponse {
|
||||
engine_result_code: number
|
||||
engine_result_message: string
|
||||
tx_blob: string
|
||||
tx_json: Transaction
|
||||
tx_json: Transaction & { hash?: string }
|
||||
accepted: boolean
|
||||
account_sequence_available: number
|
||||
account_sequence_next: number
|
||||
|
||||
@@ -14,6 +14,6 @@ export interface SubmitMultisignedResponse extends BaseResponse {
|
||||
engine_result_code: number
|
||||
engine_result_message: string
|
||||
tx_blob: string
|
||||
tx_json: Transaction
|
||||
tx_json: Transaction & { hash?: string }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ export interface TransactionStream extends BaseStream {
|
||||
meta?: TransactionMetadata
|
||||
transaction: Transaction
|
||||
validated?: boolean
|
||||
warnings?: Array<{ id: number; message: string }>
|
||||
}
|
||||
|
||||
export interface PeerStatusStream extends BaseStream {
|
||||
|
||||
@@ -14,8 +14,8 @@ export interface TxRequest extends BaseRequest {
|
||||
export interface TxResponse extends BaseResponse {
|
||||
result: {
|
||||
hash: string
|
||||
ledger_index: number
|
||||
meta: TransactionMetadata | string
|
||||
ledger_index?: number
|
||||
meta?: TransactionMetadata | string
|
||||
validated?: boolean
|
||||
} & Transaction
|
||||
searched_all?: boolean
|
||||
|
||||
@@ -2,16 +2,14 @@ import BigNumber from 'bignumber.js'
|
||||
import { xAddressToClassicAddress, isValidXAddress } from 'ripple-address-codec'
|
||||
|
||||
import type { Client } from '..'
|
||||
import { ValidationError } from '../errors'
|
||||
import { AccountInfoRequest, LedgerRequest } from '../models/methods'
|
||||
import { ValidationError, XrplError } from '../errors'
|
||||
import { AccountInfoRequest, AccountObjectsRequest } from '../models/methods'
|
||||
import { Transaction } from '../models/transactions'
|
||||
import setTransactionFlagsToNumber from '../models/utils/flags'
|
||||
import { xrpToDrops } from '../utils'
|
||||
|
||||
// 20 drops
|
||||
// Expire unconfirmed transactions after 20 ledger versions, approximately 1 minute, by default
|
||||
const LEDGER_OFFSET = 20
|
||||
// 5 XRP
|
||||
const ACCOUNT_DELETE_FEE = 5000000
|
||||
interface ClassicAccountAndTag {
|
||||
classicAccount: string
|
||||
tag: number | false | undefined
|
||||
@@ -46,6 +44,9 @@ async function autofill<T extends Transaction>(
|
||||
if (tx.LastLedgerSequence == null) {
|
||||
promises.push(setLatestValidatedLedgerSequence(this, tx))
|
||||
}
|
||||
if (tx.TransactionType === 'AccountDelete') {
|
||||
promises.push(checkAccountDeleteBlockers(this, tx))
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(() => tx)
|
||||
}
|
||||
@@ -126,12 +127,24 @@ async function setNextValidSequenceNumber(
|
||||
const request: AccountInfoRequest = {
|
||||
command: 'account_info',
|
||||
account: tx.Account,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const data = await client.request(request)
|
||||
// eslint-disable-next-line no-param-reassign, require-atomic-updates -- param reassign is safe with no race condition
|
||||
tx.Sequence = data.result.account_data.Sequence
|
||||
}
|
||||
|
||||
async function fetchAccountDeleteFee(client: Client): Promise<BigNumber> {
|
||||
const response = await client.request({ command: 'server_state' })
|
||||
const fee = response.result.state.validated_ledger?.reserve_inc
|
||||
|
||||
if (fee == null) {
|
||||
return Promise.reject(new Error('Could not fetch Owner Reserve.'))
|
||||
}
|
||||
|
||||
return new BigNumber(fee)
|
||||
}
|
||||
|
||||
async function calculateFeePerTransactionType(
|
||||
client: Client,
|
||||
tx: Transaction,
|
||||
@@ -155,7 +168,7 @@ async function calculateFeePerTransactionType(
|
||||
|
||||
// AccountDelete Transaction
|
||||
if (tx.TransactionType === 'AccountDelete') {
|
||||
baseFee = new BigNumber(ACCOUNT_DELETE_FEE)
|
||||
baseFee = await fetchAccountDeleteFee(client)
|
||||
}
|
||||
|
||||
// Multi-signed Transaction
|
||||
@@ -183,14 +196,33 @@ async function setLatestValidatedLedgerSequence(
|
||||
client: Client,
|
||||
tx: Transaction,
|
||||
): Promise<void> {
|
||||
const request: LedgerRequest = {
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const data = await client.request(request)
|
||||
const ledgerSequence = data.result.ledger_index
|
||||
const ledgerSequence = await client.getLedgerIndex()
|
||||
// eslint-disable-next-line no-param-reassign -- param reassign is safe
|
||||
tx.LastLedgerSequence = ledgerSequence + LEDGER_OFFSET
|
||||
}
|
||||
|
||||
async function checkAccountDeleteBlockers(
|
||||
client: Client,
|
||||
tx: Transaction,
|
||||
): Promise<void> {
|
||||
const request: AccountObjectsRequest = {
|
||||
command: 'account_objects',
|
||||
account: tx.Account,
|
||||
ledger_index: 'validated',
|
||||
deletion_blockers_only: true,
|
||||
}
|
||||
const response = await client.request(request)
|
||||
return new Promise((resolve, reject) => {
|
||||
if (response.result.account_objects.length > 0) {
|
||||
reject(
|
||||
new XrplError(
|
||||
`Account ${tx.Account} cannot be deleted; there are Escrows, PayChannels, RippleStates, or Checks associated with the account.`,
|
||||
response.result.account_objects,
|
||||
),
|
||||
)
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
|
||||
export default autofill
|
||||
|
||||
@@ -8,7 +8,6 @@ const BASE_10 = 10
|
||||
/**
|
||||
* Calculates the current transaction fee for the ledger.
|
||||
* Note: This is a public API that can be called directly.
|
||||
* This is not used by the `prepare*` methods. See `src/transaction/utils.ts`.
|
||||
*
|
||||
* @param this - The Client used to connect to the ledger.
|
||||
* @param cushion - The fee cushion to use.
|
||||
|
||||
15
src/sugar/ledgerIndex.ts
Normal file
15
src/sugar/ledgerIndex.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { Client } from '..'
|
||||
|
||||
/**
|
||||
* Returns the index of the most recently validated ledger.
|
||||
*
|
||||
* @param this - The Client used to connect to the ledger.
|
||||
* @returns The ledger index.
|
||||
*/
|
||||
export default async function getLedgerIndex(this: Client): Promise<number> {
|
||||
const ledgerResponse = await this.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
return ledgerResponse.result.ledger_index
|
||||
}
|
||||
@@ -54,7 +54,7 @@ async function getOrderbook(
|
||||
command: 'book_offers',
|
||||
taker_pays: takerPays,
|
||||
taker_gets: takerGets,
|
||||
ledger_index: options.ledger_index,
|
||||
ledger_index: options.ledger_index ?? 'validated',
|
||||
ledger_hash: options.ledger_hash,
|
||||
limit: options.limit ?? DEFAULT_LIMIT,
|
||||
taker: options.taker,
|
||||
|
||||
@@ -51,6 +51,7 @@ async function submitSignedTransaction(
|
||||
const request: SubmitRequest = {
|
||||
command: 'submit',
|
||||
tx_blob: signedTxEncoded,
|
||||
fail_hard: isAccountDelete(signedTransaction),
|
||||
}
|
||||
return this.request(request)
|
||||
}
|
||||
@@ -63,4 +64,9 @@ function isSigned(transaction: Transaction | string): boolean {
|
||||
)
|
||||
}
|
||||
|
||||
function isAccountDelete(transaction: Transaction | string): boolean {
|
||||
const tx = typeof transaction === 'string' ? decode(transaction) : transaction
|
||||
return tx.TransactionType === 'AccountDelete'
|
||||
}
|
||||
|
||||
export { submitTransaction, submitSignedTransaction }
|
||||
|
||||
@@ -32,7 +32,12 @@ import {
|
||||
computePaymentChannelHash,
|
||||
} from './hashes'
|
||||
import signPaymentChannelClaim from './signPaymentChannelClaim'
|
||||
import { rippleTimeToISOTime, ISOTimeToRippleTime } from './timeConversion'
|
||||
import {
|
||||
rippleTimeToISOTime,
|
||||
ISOTimeToRippleTime,
|
||||
rippleTimeToUnixTime,
|
||||
unixTimeToRippleTime,
|
||||
} from './timeConversion'
|
||||
import verifyPaymentChannelClaim from './verifyPaymentChannelClaim'
|
||||
import { xrpToDrops, dropsToXrp } from './xrpConversion'
|
||||
|
||||
@@ -51,6 +56,17 @@ function isValidSecret(secret: string): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a given address is a valid X-Address or a valid classic
|
||||
* address.
|
||||
*
|
||||
* @param address - Address to validate.
|
||||
* @returns True if address is a valid X-Address or classic address.
|
||||
*/
|
||||
function isValidAddress(address: string): boolean {
|
||||
return isValidXAddress(address) || isValidClassicAddress(address)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes undefined values from an object.
|
||||
*
|
||||
@@ -86,7 +102,10 @@ export {
|
||||
removeUndefined,
|
||||
rippleTimeToISOTime,
|
||||
ISOTimeToRippleTime,
|
||||
rippleTimeToUnixTime,
|
||||
unixTimeToRippleTime,
|
||||
isValidSecret,
|
||||
isValidAddress,
|
||||
computeSignedTransactionHash,
|
||||
computeBinaryTransactionSigningHash,
|
||||
computeAccountRootIndex,
|
||||
|
||||
@@ -6,7 +6,7 @@ const RIPPLE_EPOCH_DIFF = 0x386d4380
|
||||
* @param rpepoch - (seconds since 1/1/2000 GMT).
|
||||
* @returns Milliseconds since unix epoch.
|
||||
*/
|
||||
function rippleToUnixTimestamp(rpepoch: number): number {
|
||||
function rippleTimeToUnixTime(rpepoch: number): number {
|
||||
return (rpepoch + RIPPLE_EPOCH_DIFF) * 1000
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ function rippleToUnixTimestamp(rpepoch: number): number {
|
||||
* @param timestamp - (ms since unix epoch).
|
||||
* @returns Seconds since Ripple Epoch (1/1/2000 GMT).
|
||||
*/
|
||||
function unixToRippleTimestamp(timestamp: number): number {
|
||||
function unixTimeToRippleTime(timestamp: number): number {
|
||||
return Math.round(timestamp / 1000) - RIPPLE_EPOCH_DIFF
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ function unixToRippleTimestamp(timestamp: number): number {
|
||||
* @returns Iso8601 international standard date format.
|
||||
*/
|
||||
function rippleTimeToISOTime(rippleTime: number): string {
|
||||
return new Date(rippleToUnixTimestamp(rippleTime)).toISOString()
|
||||
return new Date(rippleTimeToUnixTime(rippleTime)).toISOString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,7 +37,12 @@ function rippleTimeToISOTime(rippleTime: number): string {
|
||||
* @returns Seconds since ripple epoch (1/1/2000 GMT).
|
||||
*/
|
||||
function ISOTimeToRippleTime(iso8601: string): number {
|
||||
return unixToRippleTimestamp(Date.parse(iso8601))
|
||||
return unixTimeToRippleTime(Date.parse(iso8601))
|
||||
}
|
||||
|
||||
export { rippleTimeToISOTime, ISOTimeToRippleTime }
|
||||
export {
|
||||
rippleTimeToUnixTime,
|
||||
unixTimeToRippleTime,
|
||||
rippleTimeToISOTime,
|
||||
ISOTimeToRippleTime,
|
||||
}
|
||||
|
||||
@@ -28,16 +28,16 @@ const MAX_ATTEMPTS = 20
|
||||
/**
|
||||
* Generates a random wallet with some amount of XRP (usually 1000 XRP).
|
||||
*
|
||||
* @param client - Client.
|
||||
* @param this - Client.
|
||||
* @param wallet - An existing XRPL Wallet to fund, if undefined, a new Wallet will be created.
|
||||
* @returns A Wallet on the Testnet or Devnet that contains some amount of XRP.
|
||||
* @throws When either Client isn't connected or unable to fund wallet address.
|
||||
*/
|
||||
async function generateFaucetWallet(
|
||||
client: Client,
|
||||
this: Client,
|
||||
wallet?: Wallet,
|
||||
): Promise<Wallet | undefined> {
|
||||
if (!client.isConnected()) {
|
||||
): Promise<Wallet> {
|
||||
if (!this.isConnected()) {
|
||||
throw new RippledError('Client not connected, cannot call faucet')
|
||||
}
|
||||
|
||||
@@ -48,27 +48,27 @@ async function generateFaucetWallet(
|
||||
: Wallet.generate()
|
||||
|
||||
// Create the POST request body
|
||||
const postBody = new TextEncoder().encode(
|
||||
JSON.stringify({
|
||||
destination: fundWallet.classicAddress,
|
||||
}),
|
||||
)
|
||||
// Retrieve the existing account balance
|
||||
const addressToFundBalance = await getAddressXrpBalance(
|
||||
client,
|
||||
fundWallet.classicAddress,
|
||||
const postBody = Buffer.from(
|
||||
new TextEncoder().encode(
|
||||
JSON.stringify({
|
||||
destination: fundWallet.classicAddress,
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
// Check the address balance is not undefined and is a number
|
||||
const startingBalance =
|
||||
addressToFundBalance && !Number.isNaN(Number(addressToFundBalance))
|
||||
? Number(addressToFundBalance)
|
||||
: 0
|
||||
let startingBalance = 0
|
||||
try {
|
||||
startingBalance = Number(
|
||||
await getAddressXrpBalance(this, fundWallet.classicAddress),
|
||||
)
|
||||
} catch {
|
||||
/* startingBalance remains '0' */
|
||||
}
|
||||
|
||||
// Options to pass to https.request
|
||||
const options = getOptions(client, postBody)
|
||||
const options = getOptions(this, postBody)
|
||||
|
||||
return returnPromise(options, client, startingBalance, fundWallet, postBody)
|
||||
return returnPromise(options, this, startingBalance, fundWallet, postBody)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-params -- Helper function created for organizational purposes
|
||||
@@ -77,8 +77,8 @@ async function returnPromise(
|
||||
client: Client,
|
||||
startingBalance: number,
|
||||
fundWallet: Wallet,
|
||||
postBody: Uint8Array,
|
||||
): Promise<Wallet | undefined> {
|
||||
postBody: Buffer,
|
||||
): Promise<Wallet> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = httpsRequest(options, (response) => {
|
||||
const chunks: Uint8Array[] = []
|
||||
@@ -127,7 +127,7 @@ async function onEnd(
|
||||
client: Client,
|
||||
startingBalance: number,
|
||||
fundWallet: Wallet,
|
||||
resolve: (wallet?: Wallet) => void,
|
||||
resolve: (wallet: Wallet) => void,
|
||||
reject: (err: ErrorConstructor | Error | unknown) => void,
|
||||
): Promise<void> {
|
||||
const body = Buffer.concat(chunks).toString()
|
||||
@@ -161,7 +161,7 @@ async function processSuccessfulResponse(
|
||||
body: string,
|
||||
startingBalance: number,
|
||||
fundWallet: Wallet,
|
||||
resolve: (wallet?: Wallet) => void,
|
||||
resolve: (wallet: Wallet) => void,
|
||||
reject: (err: ErrorConstructor | Error | unknown) => void,
|
||||
): Promise<void> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- We know this is safe and correct
|
||||
@@ -212,17 +212,17 @@ async function getAddressXrpBalance(
|
||||
): Promise<string> {
|
||||
// Get all the account balances
|
||||
try {
|
||||
const balances = await client.getBalances(address)
|
||||
const balances = await client.request({
|
||||
command: 'account_info',
|
||||
account: address,
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
|
||||
// Retrieve the XRP balance
|
||||
const xrpBalance = balances.filter(
|
||||
(balance) => balance.currency.toUpperCase() === 'XRP',
|
||||
)
|
||||
return xrpBalance[0].value
|
||||
return balances.result.account_data.Balance
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
throw new XRPLFaucetError(
|
||||
`Unable to retrieve ${address} balance. Error: ${err.message}`,
|
||||
`Unable to retrieve balance of ${address}. Error: ${err.message}`,
|
||||
)
|
||||
}
|
||||
throw err
|
||||
@@ -254,7 +254,13 @@ async function hasAddressBalanceIncreased(
|
||||
}
|
||||
|
||||
try {
|
||||
const newBalance = Number(await getAddressXrpBalance(client, address))
|
||||
let newBalance
|
||||
try {
|
||||
newBalance = Number(await getAddressXrpBalance(client, address))
|
||||
} catch {
|
||||
/* newBalance remains undefined */
|
||||
}
|
||||
|
||||
if (newBalance > originalBalance) {
|
||||
clearInterval(interval)
|
||||
resolve(true)
|
||||
@@ -279,6 +285,7 @@ async function hasAddressBalanceIncreased(
|
||||
*
|
||||
* @param client - Client.
|
||||
* @returns A {@link FaucetNetwork}.
|
||||
* @throws When the client url is not on altnet or devnet.
|
||||
*/
|
||||
function getFaucetUrl(client: Client): FaucetNetwork | undefined {
|
||||
const connectionUrl = client.connection.getUrl()
|
||||
@@ -292,7 +299,7 @@ function getFaucetUrl(client: Client): FaucetNetwork | undefined {
|
||||
return FaucetNetwork.Devnet
|
||||
}
|
||||
|
||||
return undefined
|
||||
throw new XRPLFaucetError('Faucet URL is not defined or inferrable.')
|
||||
}
|
||||
|
||||
export default generateFaucetWallet
|
||||
|
||||
@@ -3,17 +3,23 @@ import path from 'path'
|
||||
import { expect, assert } from 'chai'
|
||||
import puppeteer from 'puppeteer'
|
||||
|
||||
const TIMEOUT = 60000
|
||||
describe('Browser Tests', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
it('Integration Tests', async function () {
|
||||
const browser = await puppeteer.launch({ headless: true })
|
||||
try {
|
||||
const page = await browser.newPage().catch()
|
||||
page.setDefaultNavigationTimeout(0)
|
||||
|
||||
await page.goto(
|
||||
path.join('file:///', __dirname, '../localIntegrationRunner.html'),
|
||||
)
|
||||
|
||||
await page.waitForFunction(
|
||||
'document.querySelector("body").innerText.includes("submit multisigned transaction")',
|
||||
{ timeout: TIMEOUT },
|
||||
)
|
||||
|
||||
const fails = await page.evaluate(() => {
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { AccountDelete, EscrowFinish, Payment, Transaction } from 'xrpl-local'
|
||||
import {
|
||||
XrplError,
|
||||
AccountDelete,
|
||||
EscrowFinish,
|
||||
Payment,
|
||||
Transaction,
|
||||
} from 'xrpl-local'
|
||||
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertRejects } from '../testUtils'
|
||||
|
||||
const Fee = '10'
|
||||
const Sequence = 1432
|
||||
@@ -71,6 +78,27 @@ describe('client.autofill', function () {
|
||||
assert.strictEqual(txResult.Sequence, 23)
|
||||
})
|
||||
|
||||
it('should throw error if account deletion blockers exist', async function () {
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse(
|
||||
'account_objects',
|
||||
rippled.account_objects.normal,
|
||||
)
|
||||
|
||||
const tx: AccountDelete = {
|
||||
Account: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn',
|
||||
TransactionType: 'AccountDelete',
|
||||
Destination: 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
|
||||
Fee,
|
||||
Sequence,
|
||||
LastLedgerSequence,
|
||||
}
|
||||
|
||||
await assertRejects(this.client.autofill(tx), XrplError)
|
||||
})
|
||||
|
||||
describe('when autofill Fee is missing', function () {
|
||||
it('should autofill Fee of a Transaction', async function () {
|
||||
const tx: Transaction = {
|
||||
@@ -80,17 +108,7 @@ describe('client.autofill', function () {
|
||||
Sequence,
|
||||
LastLedgerSequence,
|
||||
}
|
||||
this.mockRippled.addResponse('server_info', {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
info: {
|
||||
validated_ledger: {
|
||||
base_fee_xrp: 0.00001,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
const txResult = await this.client.autofill(tx)
|
||||
|
||||
assert.strictEqual(txResult.Fee, '12')
|
||||
@@ -108,19 +126,9 @@ describe('client.autofill', function () {
|
||||
}
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
this.mockRippled.addResponse('server_info', {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
info: {
|
||||
validated_ledger: {
|
||||
base_fee_xrp: 0.00001,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
const txResult = await this.client.autofill(tx)
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
|
||||
const txResult = await this.client.autofill(tx)
|
||||
assert.strictEqual(txResult.Fee, '399')
|
||||
})
|
||||
|
||||
@@ -132,20 +140,25 @@ describe('client.autofill', function () {
|
||||
}
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
this.mockRippled.addResponse('server_info', {
|
||||
this.mockRippled.addResponse('server_state', {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
info: {
|
||||
state: {
|
||||
validated_ledger: {
|
||||
base_fee_xrp: 0.00001,
|
||||
reserve_inc: 2000000,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse(
|
||||
'account_objects',
|
||||
rippled.account_objects.empty,
|
||||
)
|
||||
const txResult = await this.client.autofill(tx)
|
||||
|
||||
assert.strictEqual(txResult.Fee, '5000000')
|
||||
assert.strictEqual(txResult.Fee, '2000000')
|
||||
})
|
||||
|
||||
it('should autofill Fee of an EscrowFinish transaction with signersCount', async function () {
|
||||
@@ -160,17 +173,7 @@ describe('client.autofill', function () {
|
||||
}
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
this.mockRippled.addResponse('server_info', {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
info: {
|
||||
validated_ledger: {
|
||||
base_fee_xrp: 0.00001,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
const txResult = await this.client.autofill(tx, 4)
|
||||
|
||||
assert.strictEqual(txResult.Fee, '459')
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { XrplError, NotFoundError } from '../../src'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
|
||||
describe('client errors', function () {
|
||||
@@ -7,12 +8,12 @@ describe('client errors', function () {
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('XrplError with data', async function () {
|
||||
const error = new this.client.errors.XrplError('_message_', '_data_')
|
||||
const error = new XrplError('_message_', '_data_')
|
||||
assert.strictEqual(error.toString(), "[XrplError(_message_, '_data_')]")
|
||||
})
|
||||
|
||||
it('NotFoundError default message', async function () {
|
||||
const error = new this.client.errors.NotFoundError()
|
||||
const error = new NotFoundError()
|
||||
assert.strictEqual(error.toString(), '[NotFoundError(Not found)]')
|
||||
})
|
||||
})
|
||||
|
||||
15
test/client/getLedgerIndex.ts
Normal file
15
test/client/getLedgerIndex.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
|
||||
describe('client.getLedgerIndex', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('getLedgerIndex', async function () {
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
const ledgerIndex = await this.client.getLedgerIndex()
|
||||
assert.strictEqual(ledgerIndex, 9038214)
|
||||
})
|
||||
})
|
||||
@@ -1,7 +1,7 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { BookOffersRequest } from '../../src'
|
||||
import { BookOffersRequest, ValidationError } from '../../src'
|
||||
import { OfferLedgerFlags } from '../../src/models/ledger/offer'
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
@@ -101,7 +101,7 @@ describe('client.getOrderbook', function () {
|
||||
invalid: 'options',
|
||||
},
|
||||
),
|
||||
this.client.errors.ValidationError,
|
||||
ValidationError,
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
154
test/client/partialPayments.ts
Normal file
154
test/client/partialPayments.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any -- required for formatting transactions */
|
||||
import { expect } from 'chai'
|
||||
|
||||
import type { TransactionStream } from '../../src'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
|
||||
const partialPaymentIOU = rippled.partial_payments.iou
|
||||
const partialPaymentXRP = rippled.partial_payments.xrp
|
||||
|
||||
describe('client handling of tfPartialPayments', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('Tx with no tfPartialPayment', async function () {
|
||||
this.mockRippled.addResponse('tx', rippled.tx.Payment)
|
||||
const resp = await this.client.request({ command: 'tx' })
|
||||
|
||||
expect(resp.warnings).to.equal(undefined)
|
||||
})
|
||||
|
||||
it('Tx with IOU tfPartialPayment', async function () {
|
||||
const mockResponse = { ...rippled.tx.Payment, result: partialPaymentIOU }
|
||||
this.mockRippled.addResponse('tx', mockResponse)
|
||||
const resp = await this.client.request({ command: 'tx' })
|
||||
|
||||
expect(resp.warnings).to.deep.equal([
|
||||
{
|
||||
id: 2001,
|
||||
message: 'This response contains a Partial Payment',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('Tx with XRP tfPartialPayment', async function () {
|
||||
const mockResponse = { ...rippled.tx.Payment, result: partialPaymentXRP }
|
||||
this.mockRippled.addResponse('tx', mockResponse)
|
||||
const resp = await this.client.request({ command: 'tx' })
|
||||
|
||||
expect(resp.warnings).to.deep.equal([
|
||||
{
|
||||
id: 2001,
|
||||
message: 'This response contains a Partial Payment',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('account_tx with no tfPartialPayment', async function () {
|
||||
this.mockRippled.addResponse('account_tx', rippled.account_tx.normal)
|
||||
const resp = await this.client.request({ command: 'account_tx' })
|
||||
|
||||
expect(resp.warnings).to.equal(undefined)
|
||||
})
|
||||
|
||||
it('account_tx with IOU tfPartialPayment', async function () {
|
||||
const partial = {
|
||||
...rippled.tx.Payment,
|
||||
result: partialPaymentIOU,
|
||||
}
|
||||
const mockResponse = rippled.account_tx.normal
|
||||
mockResponse.result.transactions.push({
|
||||
tx: partial.result,
|
||||
meta: partial.result.meta,
|
||||
} as any)
|
||||
|
||||
this.mockRippled.addResponse('account_tx', mockResponse)
|
||||
const resp = await this.client.request({
|
||||
command: 'account_tx',
|
||||
account: mockResponse.result.account,
|
||||
})
|
||||
|
||||
expect(resp.warnings).to.deep.equal([
|
||||
{
|
||||
id: 2001,
|
||||
message: 'This response contains a Partial Payment',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('account_tx with XRP tfPartialPayment', async function () {
|
||||
// TODO: Create fixtues with partial payments instead of using ...
|
||||
const partial = { ...rippled.tx.Payment, result: partialPaymentXRP }
|
||||
const mockResponse = rippled.account_tx.normal
|
||||
mockResponse.result.transactions.push({
|
||||
tx: partial.result,
|
||||
meta: partial.result.meta,
|
||||
} as any)
|
||||
|
||||
this.mockRippled.addResponse('account_tx', mockResponse)
|
||||
const resp = await this.client.request({
|
||||
command: 'account_tx',
|
||||
account: mockResponse.result.account,
|
||||
})
|
||||
|
||||
expect(resp.warnings).to.deep.equal([
|
||||
{
|
||||
id: 2001,
|
||||
message: 'This response contains a Partial Payment',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('transaction_entry with no tfPartialPayment', async function () {
|
||||
this.mockRippled.addResponse('transaction_entry', rippled.transaction_entry)
|
||||
const resp = await this.client.request({ command: 'transaction_entry' })
|
||||
|
||||
expect(resp.warnings).to.equal(undefined)
|
||||
})
|
||||
|
||||
it('transaction_entry with XRP tfPartialPayment', async function () {
|
||||
const mockResponse = rippled.transaction_entry
|
||||
mockResponse.result.tx_json.Amount = '1000'
|
||||
this.mockRippled.addResponse('transaction_entry', rippled.transaction_entry)
|
||||
const resp = await this.client.request({ command: 'transaction_entry' })
|
||||
|
||||
expect(resp.warnings).to.deep.equal([
|
||||
{
|
||||
id: 2001,
|
||||
message: 'This response contains a Partial Payment',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('Transactions stream with no tfPartialPayment', async function (done) {
|
||||
this.mockRippled.addResponse('transaction_entry', rippled.transaction_entry)
|
||||
this.client.on('transaction', (tx: TransactionStream) => {
|
||||
expect(tx.warnings).to.equal(undefined)
|
||||
done()
|
||||
})
|
||||
|
||||
this.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.transaction),
|
||||
)
|
||||
})
|
||||
|
||||
it('Transactions stream with XRP tfPartialPayment', async function (done) {
|
||||
this.mockRippled.addResponse('transaction_entry', rippled.transaction_entry)
|
||||
this.client.on('transaction', (tx: TransactionStream) => {
|
||||
expect(tx.warnings).to.deep.equal([
|
||||
{
|
||||
id: 2001,
|
||||
message: 'This response contains a Partial Payment',
|
||||
},
|
||||
])
|
||||
done()
|
||||
})
|
||||
|
||||
const partial: any = rippled.streams.transaction
|
||||
partial.transaction = rippled.tx.Payment.result
|
||||
partial.meta.delivered_amount = '1000'
|
||||
partial.transaction.Flags = 0x00020000
|
||||
this.client.connection.onMessage(JSON.stringify(partial))
|
||||
})
|
||||
})
|
||||
@@ -62,7 +62,7 @@ describe('client.submitSignedTransaction', function () {
|
||||
|
||||
this.mockRippled.addResponse('submit', rippled.submit.success)
|
||||
|
||||
assertRejects(
|
||||
await assertRejects(
|
||||
this.client.submitSignedTransaction(signedTx),
|
||||
ValidationError,
|
||||
'Transaction must be signed',
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Connection } from 'xrpl-local/client/connection'
|
||||
|
||||
import rippled from './fixtures/rippled'
|
||||
import { setupClient, teardownClient } from './setupClient'
|
||||
import { ignoreWebSocketDisconnect } from './testUtils'
|
||||
import { assertRejects, ignoreWebSocketDisconnect } from './testUtils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
@@ -514,13 +514,13 @@ describe('Connection', function () {
|
||||
this.client.on('error', (errorCode, errorMessage, message) => {
|
||||
assert.strictEqual(errorCode, 'badMessage')
|
||||
assert.strictEqual(errorMessage, 'valid id not found in response')
|
||||
assert.strictEqual(message, '{"type":"response","id":"must be integer"}')
|
||||
assert.strictEqual(message, '{"type":"response","id":{}}')
|
||||
done()
|
||||
})
|
||||
this.client.connection.onMessage(
|
||||
JSON.stringify({
|
||||
type: 'response',
|
||||
id: 'must be integer',
|
||||
id: {},
|
||||
}),
|
||||
)
|
||||
})
|
||||
@@ -619,4 +619,20 @@ describe('Connection', function () {
|
||||
.then(() => new Error('Should not have succeeded'))
|
||||
.catch(done())
|
||||
})
|
||||
|
||||
it('should throw error if pending response with same ID', async function () {
|
||||
const promise1 = this.client.connection.request({
|
||||
id: 'test',
|
||||
command: 'ping',
|
||||
})
|
||||
const promise2 = this.client.connection.request({
|
||||
id: 'test',
|
||||
command: 'ping',
|
||||
})
|
||||
await assertRejects(
|
||||
Promise.all([promise1, promise2]),
|
||||
XrplError,
|
||||
"Response with id 'test' is already pending",
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
13
test/fixtures/rippled/accountObjectsEmpty.json
vendored
Normal file
13
test/fixtures/rippled/accountObjectsEmpty.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"id": 1,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"account_objects": [],
|
||||
"ledger_hash":
|
||||
"053DF17D2289D1C4971C22F235BC1FCA7D4B3AE966F842E5819D0749E0B8ECD3",
|
||||
"ledger_index": 14378733,
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
239
test/fixtures/rippled/accountTx.js
vendored
239
test/fixtures/rippled/accountTx.js
vendored
@@ -1,239 +0,0 @@
|
||||
/* eslint-disable max-len */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const hashes = require('../hashes');
|
||||
const addresses = require('../addresses');
|
||||
const AccountSet = require('./tx/accountSet.json');
|
||||
const NotFound = require('./tx/notFound.json');
|
||||
const binary = require('ripple-binary-codec');
|
||||
|
||||
module.exports = function(request, options = {}) {
|
||||
_.defaults(options, {
|
||||
memos: [{
|
||||
Memo: {
|
||||
MemoFormat: '7274312E352E32',
|
||||
MemoType: '636C69656E74'
|
||||
}
|
||||
}],
|
||||
hash: hashes.VALID_TRANSACTION_HASH,
|
||||
validated: true
|
||||
});
|
||||
|
||||
let tx = {
|
||||
Account: addresses.ACCOUNT,
|
||||
Amount: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '0.001'
|
||||
},
|
||||
Destination: addresses.ISSUER,
|
||||
Fee: '10',
|
||||
Flags: 0,
|
||||
Memos: options.memos,
|
||||
Paths: [
|
||||
[
|
||||
{
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
type: 48,
|
||||
type_hex: '0000000000000030'
|
||||
},
|
||||
{
|
||||
account: addresses.OTHER_ACCOUNT,
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}
|
||||
]
|
||||
],
|
||||
SendMax: '1112209',
|
||||
Sequence: 4,
|
||||
SigningPubKey: '02BC8C02199949B15C005B997E7C8594574E9B02BA2D0628902E0532989976CF9D',
|
||||
TransactionType: 'Payment',
|
||||
TxnSignature: '304502204EE3E9D1B01D8959B08450FCA9E22025AF503DEF310E34A93863A85CAB3C0BC5022100B61F5B567F77026E8DEED89EED0B7CAF0E6C96C228A2A65216F0DC2D04D52083'
|
||||
};
|
||||
|
||||
let meta = {
|
||||
AffectedNodes: [
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5E03E788E09BB000',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
OwnerNode: '0000000000000000',
|
||||
Sequence: 58,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
value: '5.648998'
|
||||
},
|
||||
TakerPays: '6208248802'
|
||||
},
|
||||
LedgerEntryType: 'Offer',
|
||||
LedgerIndex: '3CFB3C79D4F1BDB1EE5245259372576D926D9A875713422F7169A6CC60AFA68B',
|
||||
PreviousFields: {
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
value: '5.65'
|
||||
},
|
||||
TakerPays: '6209350000'
|
||||
},
|
||||
PreviousTxnID: '8F571C346688D89AC1F737AE3B6BB5D976702B171CC7B4DE5CA3D444D5B8D6B4',
|
||||
PreviousTxnLgrSeq: 348433
|
||||
}
|
||||
},
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Balance: {
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||
value: '-0.001'
|
||||
},
|
||||
Flags: 131072,
|
||||
HighLimit: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '1'
|
||||
},
|
||||
HighNode: '0000000000000000',
|
||||
LowLimit: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
value: '0'
|
||||
},
|
||||
LowNode: '0000000000000002'
|
||||
},
|
||||
LedgerEntryType: 'RippleState',
|
||||
LedgerIndex: '4BD1874F8F3A60EDB0C23F5BD43E07953C2B8741B226648310D113DE2B486F01',
|
||||
PreviousFields: {
|
||||
Balance: {
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||
value: '0'
|
||||
}
|
||||
},
|
||||
PreviousTxnID: '5B2006DAD0B3130F57ACF7CC5CCAC2EEBCD4B57AAA091A6FD0A24B073D08ABB8',
|
||||
PreviousTxnLgrSeq: 343703
|
||||
}
|
||||
},
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Account: addresses.ACCOUNT,
|
||||
Balance: '9998898762',
|
||||
Flags: 0,
|
||||
OwnerCount: 3,
|
||||
Sequence: 5
|
||||
},
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
LedgerIndex: '4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05',
|
||||
PreviousFields: {
|
||||
Balance: '9999999970',
|
||||
Sequence: 4
|
||||
},
|
||||
PreviousTxnID: '53354D84BAE8FDFC3F4DA879D984D24B929E7FEB9100D2AD9EFCD2E126BCCDC8',
|
||||
PreviousTxnLgrSeq: 343570
|
||||
}
|
||||
},
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Account: 'r9tGqzZgKxVFvzKFdUqXAqTzazWBUia8Qr',
|
||||
Balance: '912695302618',
|
||||
Flags: 0,
|
||||
OwnerCount: 10,
|
||||
Sequence: 59
|
||||
},
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
LedgerIndex: 'F3E119AAA87AF3607CF87F5523BB8278A83BCB4142833288305D767DD30C392A',
|
||||
PreviousFields: {
|
||||
Balance: '912694201420'
|
||||
},
|
||||
PreviousTxnID: '8F571C346688D89AC1F737AE3B6BB5D976702B171CC7B4DE5CA3D444D5B8D6B4',
|
||||
PreviousTxnLgrSeq: 348433
|
||||
}
|
||||
},
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Balance: {
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||
value: '-5.5541638883365'
|
||||
},
|
||||
Flags: 131072,
|
||||
HighLimit: {
|
||||
currency: 'USD',
|
||||
issuer: 'r9tGqzZgKxVFvzKFdUqXAqTzazWBUia8Qr',
|
||||
value: '1000'
|
||||
},
|
||||
HighNode: '0000000000000000',
|
||||
LowLimit: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
value: '0'
|
||||
},
|
||||
LowNode: '000000000000000C'
|
||||
},
|
||||
LedgerEntryType: 'RippleState',
|
||||
LedgerIndex: 'FA1255C2E0407F1945BCF9351257C7C5C28B0F5F09BB81C08D35A03E9F0136BC',
|
||||
PreviousFields: {
|
||||
Balance: {
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||
value: '-5.5551658883365'
|
||||
}
|
||||
},
|
||||
PreviousTxnID: '8F571C346688D89AC1F737AE3B6BB5D976702B171CC7B4DE5CA3D444D5B8D6B4',
|
||||
PreviousTxnLgrSeq: 348433
|
||||
}
|
||||
}
|
||||
],
|
||||
TransactionIndex: 0,
|
||||
TransactionResult: 'tesSUCCESS'
|
||||
};
|
||||
|
||||
let marker = Number(request.marker) || 0;
|
||||
marker += 1;
|
||||
if (marker === 5) {
|
||||
meta.TransactionResult = 'tecINSUFFICIENT_RESERVE';
|
||||
} else if (marker === 6) {
|
||||
tx = _.cloneDeep(AccountSet.result);
|
||||
meta = tx.meta;
|
||||
delete tx.meta;
|
||||
} else if (marker === 7) {
|
||||
tx.Account = addresses.OTHER_ACCOUNT;
|
||||
} else if (marker === 8) {
|
||||
tx.Destination = addresses.THIRD_ACCOUNT;
|
||||
} else if (marker > 25) {
|
||||
marker = undefined;
|
||||
} else if (marker > 15) {
|
||||
tx.Account = addresses.ISSUER;
|
||||
tx.Destination = addresses.ACCOUNT;
|
||||
}
|
||||
if (request.limit === 13) {
|
||||
const res = Object.assign({}, NotFound, {id: request.id});
|
||||
return JSON.stringify(res);
|
||||
}
|
||||
return JSON.stringify({
|
||||
id: request.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
marker: marker == null ? undefined : String(marker),
|
||||
transactions: [
|
||||
{
|
||||
ledger_index: 348860 - Number(marker || 100),
|
||||
tx_blob: binary.encode(tx),
|
||||
meta: binary.encode(meta),
|
||||
validated: options.validated
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
};
|
||||
194
test/fixtures/rippled/accountTx.json
vendored
Normal file
194
test/fixtures/rippled/accountTx.json
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
{
|
||||
"id": 2,
|
||||
"result": {
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 66496515,
|
||||
"ledger_index_min": 32570,
|
||||
"limit": 2,
|
||||
"marker": {
|
||||
"ledger": 61965340,
|
||||
"seq": 0
|
||||
},
|
||||
"transactions": [
|
||||
{
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"AccountTxnID": "4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB",
|
||||
"Balance": "424021949",
|
||||
"Domain": "6D64756F31332E636F6D",
|
||||
"EmailHash": "98B4375E1D753E5B91627516F6D70977",
|
||||
"Flags": 9568256,
|
||||
"MessageKey": "0000000000000000000000070000000300",
|
||||
"OwnerCount": 12,
|
||||
"RegularKey": "rD9iJmieYHn8jTtPjwwkW2Wm9sVDvPXLoJ",
|
||||
"Sequence": 385,
|
||||
"TransferRate": 4294967295
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
|
||||
"PreviousFields": {
|
||||
"AccountTxnID": "CB1BF910C93D050254C049E9003DA1A265C107E0C8DE4A7CFF55FADFD39D5656",
|
||||
"Balance": "424021959",
|
||||
"OwnerCount": 11,
|
||||
"Sequence": 384
|
||||
},
|
||||
"PreviousTxnID": "CB1BF910C93D050254C049E9003DA1A265C107E0C8DE4A7CFF55FADFD39D5656",
|
||||
"PreviousTxnLgrSeq": 61965405
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Owner": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"RootIndex": "3B9C0CE77FCE7BCEE1A68F1E26AC467AF326239D0D816CE705E4A0E2DAD03F6D"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "3B9C0CE77FCE7BCEE1A68F1E26AC467AF326239D0D816CE705E4A0E2DAD03F6D"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "43EA78783A089B137D5E87610DF3BD4129F989EDD02EFAF6C265924D3A0EF8CE",
|
||||
"PreviousTxnID": "711C4F606C63076137FAE90ADC36379D7066CF551E96DA6FE2BDAB5ECBFACF2B",
|
||||
"PreviousTxnLgrSeq": 61965340
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Owner": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"RootIndex": "6C8ECE4529AA025F51059F1B56015A8A5F49987064FBE1E832FF27BFEF3F18CF"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "6C8ECE4529AA025F51059F1B56015A8A5F49987064FBE1E832FF27BFEF3F18CF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "Check",
|
||||
"LedgerIndex": "C4A46CCD8F096E994C4B0DEAB6CE98E722FC17D7944C28B95127C2659C47CBEB",
|
||||
"NewFields": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Destination": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"DestinationTag": 13,
|
||||
"SendMax": {
|
||||
"currency": "USD",
|
||||
"issuer": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"value": "10"
|
||||
},
|
||||
"Sequence": 384
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 12,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"tx": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Destination": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"DestinationTag": 13,
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 61965654,
|
||||
"SendMax": {
|
||||
"currency": "USD",
|
||||
"issuer": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"value": "10"
|
||||
},
|
||||
"Sequence": 384,
|
||||
"SigningPubKey": "03CE5C5949DEBBBB5E6D8FA54AC3FA8A3ED4EE1C3E9617571840F9349DE7AEF329",
|
||||
"TransactionType": "CheckCreate",
|
||||
"TxnSignature": "304402200EC41D7F6C3C57E697A61EFC0585544399A1ECD7AA233256F6BE785294E2671C022022802AED958D44E6BE5679D41157246A7AA72A4A6CFBF531A39A01CCB6AFEED9",
|
||||
"date": 668134081,
|
||||
"hash": "4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB",
|
||||
"inLedger": 61965653,
|
||||
"ledger_index": 61965653
|
||||
},
|
||||
"validated": true
|
||||
},
|
||||
{
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"AccountTxnID": "CB1BF910C93D050254C049E9003DA1A265C107E0C8DE4A7CFF55FADFD39D5656",
|
||||
"Balance": "424021959",
|
||||
"Domain": "6D64756F31332E636F6D",
|
||||
"EmailHash": "98B4375E1D753E5B91627516F6D70977",
|
||||
"Flags": 9568256,
|
||||
"MessageKey": "0000000000000000000000070000000300",
|
||||
"OwnerCount": 11,
|
||||
"RegularKey": "rD9iJmieYHn8jTtPjwwkW2Wm9sVDvPXLoJ",
|
||||
"Sequence": 384,
|
||||
"TransferRate": 4294967295
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
|
||||
"PreviousFields": {
|
||||
"AccountTxnID": "711C4F606C63076137FAE90ADC36379D7066CF551E96DA6FE2BDAB5ECBFACF2B",
|
||||
"Balance": "424021969",
|
||||
"OwnerCount": 10,
|
||||
"Sequence": 383
|
||||
},
|
||||
"PreviousTxnID": "711C4F606C63076137FAE90ADC36379D7066CF551E96DA6FE2BDAB5ECBFACF2B",
|
||||
"PreviousTxnLgrSeq": 61965340
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Owner": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"RootIndex": "3B9C0CE77FCE7BCEE1A68F1E26AC467AF326239D0D816CE705E4A0E2DAD03F6D"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "3B9C0CE77FCE7BCEE1A68F1E26AC467AF326239D0D816CE705E4A0E2DAD03F6D"
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "DepositPreauth",
|
||||
"LedgerIndex": "A43898B685C450DE8E194B24D9D54E62530536A770CCB311BFEE15A27381ABB2",
|
||||
"NewFields": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Authorize": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 59,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"tx": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Authorize": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 61965405,
|
||||
"Sequence": 383,
|
||||
"SigningPubKey": "03CE5C5949DEBBBB5E6D8FA54AC3FA8A3ED4EE1C3E9617571840F9349DE7AEF329",
|
||||
"TransactionType": "DepositPreauth",
|
||||
"TxnSignature": "304402206464885794C92713D15141B8C68CD020E5EE0BADB7CA7293CB073F02594BEB6F02205FC46EF82613DB5F2AC583C854B9F3C5FAE223E9C7056CB1625260DD3E0718AC",
|
||||
"date": 668133130,
|
||||
"hash": "CB1BF910C93D050254C049E9003DA1A265C107E0C8DE4A7CFF55FADFD39D5656",
|
||||
"inLedger": 61965405,
|
||||
"ledger_index": 61965405
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
],
|
||||
"validated": true
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
15
test/fixtures/rippled/index.ts
vendored
15
test/fixtures/rippled/index.ts
vendored
@@ -1,8 +1,9 @@
|
||||
import normalAccountInfo from './accountInfo.json'
|
||||
import notfoundAccountInfo from './accountInfoNotFound.json'
|
||||
import emptyAccountObjects from './accountObjectsEmpty.json'
|
||||
import normalAccountObjects from './accountObjectsNormal.json'
|
||||
import account_offers from './accountOffers'
|
||||
import normalAccountTx from './accountTx'
|
||||
import normalAccountTx from './accountTx.json'
|
||||
import fabric from './bookOffers'
|
||||
import usd_xrp from './bookOffersUsdXrp.json'
|
||||
import xrp_usd from './bookOffersXrpUsd.json'
|
||||
@@ -23,6 +24,8 @@ import withoutCloseTime from './ledgerWithoutCloseTime.json'
|
||||
import withPartialPayment from './ledgerWithPartialPayment.json'
|
||||
import withSettingsTx from './ledgerWithSettingsTx.json'
|
||||
import withStateAsHashes from './ledgerWithStateAsHashes.json'
|
||||
import iouPartialPayment from './partialPaymentIOU.json'
|
||||
import xrpPartialPayment from './partialPaymentXRP.json'
|
||||
import generate from './pathFind'
|
||||
import sendAll from './pathFindSendAll.json'
|
||||
import sendUSD from './pathFindSendUsd.json'
|
||||
@@ -49,6 +52,7 @@ import successSubmit from './submit.json'
|
||||
import failureSubmit from './submitFailed.json'
|
||||
import successSubscribe from './subscribe.json'
|
||||
import errorSubscribe from './subscribeError.json'
|
||||
import transaction_entry from './transactionEntry.json'
|
||||
import AccountDelete from './tx/accountDelete.json'
|
||||
import AccountDeleteWithMemo from './tx/accountDeleteWithMemo.json'
|
||||
import AccountSet from './tx/accountSet.json'
|
||||
@@ -131,9 +135,14 @@ const streams = {
|
||||
manifest: manifestStream,
|
||||
}
|
||||
|
||||
const partial_payments = {
|
||||
xrp: xrpPartialPayment,
|
||||
iou: iouPartialPayment,
|
||||
}
|
||||
|
||||
const account_objects = {
|
||||
normal: normalAccountObjects,
|
||||
// notfound: notfoundAccountObjects
|
||||
empty: emptyAccountObjects,
|
||||
}
|
||||
|
||||
const account_info = {
|
||||
@@ -249,12 +258,14 @@ const rippled = {
|
||||
ledger_data,
|
||||
ledger_entry,
|
||||
ledger_current,
|
||||
partial_payments,
|
||||
path_find,
|
||||
payment_channel,
|
||||
server_info,
|
||||
streams,
|
||||
submit,
|
||||
subscribe,
|
||||
transaction_entry,
|
||||
tx,
|
||||
unsubscribe,
|
||||
}
|
||||
|
||||
5
test/fixtures/rippled/ledger.json
vendored
5
test/fixtures/rippled/ledger.json
vendored
@@ -20,6 +20,9 @@
|
||||
"1FC4D12C30CE206A6E23F46FAC62BD393BE9A79A1C452C6F3A04A13BC7A5E5A3",
|
||||
"E25C38FDB8DD4A2429649588638EE05D055EE6D839CABAF8ABFB4BD17CFE1F3E"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ledger_hash": "1723099E269C77C4BDE86C83FA6415D71CF20AA5CB4A94E5C388ED97123FB55B",
|
||||
"ledger_index": 9038214,
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
|
||||
116
test/fixtures/rippled/partialPaymentIOU.json
vendored
Normal file
116
test/fixtures/rippled/partialPaymentIOU.json
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "10"
|
||||
},
|
||||
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
|
||||
"Fee": "10000",
|
||||
"Flags": 131072,
|
||||
"Sequence": 23295,
|
||||
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
|
||||
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
|
||||
"Balance": "1930599790",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 2,
|
||||
"Sequence": 23296
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "267C16D24EC42EEF8B03D5BE4E94266B1675FA54AFCE42DE795E02AB61031CBD",
|
||||
"PreviousFields": {
|
||||
"Balance": "1930609790",
|
||||
"Sequence": 23295
|
||||
},
|
||||
"PreviousTxnID": "0F5396388E91D37BB26C8E24073A57E7C5D51E79AEE4CD855653B8499AE4E3DD",
|
||||
"PreviousTxnLgrSeq": 22419806
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-9.980959751659681"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
|
||||
"value": "1000000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000423"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "C66957AF25229357F9C2D2BA17CE47D88169788EDA7610AD0F29AD5BCB225EE5",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.0009198315"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "2A01E994D7000000B43DD63825A081B4440A44AB2F6FA0D506158AC9CA6B2869",
|
||||
"PreviousTxnLgrSeq": 22420532
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-276666.975959"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
|
||||
"value": "1000000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "00000000000002D7"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "FFD710AE2074A98D920D00CC352F25744899F069A6C1B9E31DD32D2C6606E615",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-276676.975959"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "BB9DFC87E9D4ED09CA2726DDFE83A4A396ED0D6545536322DE17CDACF45C0D5B",
|
||||
"PreviousTxnLgrSeq": 22419307
|
||||
}
|
||||
}
|
||||
],
|
||||
"delivered_amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "9.980039920159681"
|
||||
},
|
||||
"TransactionIndex": 5,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
}
|
||||
}
|
||||
108
test/fixtures/rippled/partialPaymentXRP.json
vendored
Normal file
108
test/fixtures/rippled/partialPaymentXRP.json
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
|
||||
"Amount": "2000000",
|
||||
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
|
||||
"Fee": "10000",
|
||||
"Flags": 131072,
|
||||
"Sequence": 23295,
|
||||
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
|
||||
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
|
||||
"Balance": "1930599790",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 2,
|
||||
"Sequence": 23296
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "267C16D24EC42EEF8B03D5BE4E94266B1675FA54AFCE42DE795E02AB61031CBD",
|
||||
"PreviousFields": {
|
||||
"Balance": "1930609790",
|
||||
"Sequence": 23295
|
||||
},
|
||||
"PreviousTxnID": "0F5396388E91D37BB26C8E24073A57E7C5D51E79AEE4CD855653B8499AE4E3DD",
|
||||
"PreviousTxnLgrSeq": 22419806
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-9.980959751659681"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
|
||||
"value": "1000000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000423"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "C66957AF25229357F9C2D2BA17CE47D88169788EDA7610AD0F29AD5BCB225EE5",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.0009198315"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "2A01E994D7000000B43DD63825A081B4440A44AB2F6FA0D506158AC9CA6B2869",
|
||||
"PreviousTxnLgrSeq": 22420532
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-276666.975959"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
|
||||
"value": "1000000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "00000000000002D7"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "FFD710AE2074A98D920D00CC352F25744899F069A6C1B9E31DD32D2C6606E615",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-276676.975959"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "BB9DFC87E9D4ED09CA2726DDFE83A4A396ED0D6545536322DE17CDACF45C0D5B",
|
||||
"PreviousTxnLgrSeq": 22419307
|
||||
}
|
||||
}
|
||||
],
|
||||
"delivered_amount": "1000000",
|
||||
"TransactionIndex": 5,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
}
|
||||
}
|
||||
75
test/fixtures/rippled/transactionEntry.json
vendored
Normal file
75
test/fixtures/rippled/transactionEntry.json
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"id": 4,
|
||||
"result": {
|
||||
"ledger_hash": "C3D46598EB9BF92688CE2395496AE3A55E084F57319F1086B7CD5CF002049097",
|
||||
"ledger_index": 66499739,
|
||||
"metadata": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rLSn6Z3T8uCxbcd1oxwfGQN1Fdn5CyGujK",
|
||||
"Balance": "1750880278055",
|
||||
"Flags": 131072,
|
||||
"MessageKey": "02000000000000000000000000B5F84807633600D3AF4D922486E0ADF9FA5F6359",
|
||||
"OwnerCount": 0,
|
||||
"Sequence": 731413
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "D087F0DCA3A847606D90DB606FBB85B7A3334B9AD341E30E98B1653261019708",
|
||||
"PreviousFields": {
|
||||
"Balance": "1750984454027",
|
||||
"Sequence": 731412
|
||||
},
|
||||
"PreviousTxnID": "9CD134C7FCFFEC73381E32190BA7A963B681CB1A1AE84923AD38A5CD96ABDA47",
|
||||
"PreviousTxnLgrSeq": 66499731
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh",
|
||||
"Balance": "86353857604",
|
||||
"Flags": 131072,
|
||||
"OwnerCount": 0,
|
||||
"Sequence": 314878
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "E50C9EE857E177CE38071B8930F66053C9C86DF9B8ADEDA632CB9DFF50EC0033",
|
||||
"PreviousFields": {
|
||||
"Balance": "86249687632"
|
||||
},
|
||||
"PreviousTxnID": "B424651D147B2D6D625AF9F27B4F4030EBBA0DB0A7684D0D84ED23ED0FCC27B2",
|
||||
"PreviousTxnLgrSeq": 66499738
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 57,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"delivered_amount": "104169972"
|
||||
},
|
||||
"tx_json": {
|
||||
"Account": "rLSn6Z3T8uCxbcd1oxwfGQN1Fdn5CyGujK",
|
||||
"Amount": "104169972",
|
||||
"Destination": "rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh",
|
||||
"DestinationTag": 109735445,
|
||||
"Fee": "6000",
|
||||
"Flags": 2147614720,
|
||||
"LastLedgerSequence": 66499838,
|
||||
"Sequence": 731412,
|
||||
"SigningPubKey": "038944E15BADB379B5A2173B5248F36178DB08ABFF69428266D4068A1A471E3F11",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "3044022060CA007B76E2835EE03AC67B96C9FFF0C946AC19CFD9AAB7E77AB87F8E36239A02204F86B31BCF58C2472334D44364F3FD6528036C415028690F29C85E818DDC676F",
|
||||
"hash": "3F437BAAC9E713F24DF2954EADB7BE80F608D8B758116298B999BA252DF4816C"
|
||||
},
|
||||
"validated": true,
|
||||
"warnings": [
|
||||
{
|
||||
"id": 1004,
|
||||
"message": "This is a reporting server. The default behavior of a reporting server is to only return validated data. If you are looking for not yet validated data, include \"ledger_index : current\" in your request, which will cause this server to forward the request to a p2p node. If the forward is successful the response will include \"forwarded\" : \"true\""
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
@@ -2,7 +2,7 @@ To run integration tests:
|
||||
1. Run rippled-standalone node, either in a docker container (preferred) or by installing rippled.
|
||||
* With docker, run `docker run -p 6006:6006 -it natenichols/rippled-standalone:latest`
|
||||
* Or [download and build rippled](https://xrpl.org/install-rippled.html) and run `./rippled -a`
|
||||
2. Run `yarn test:integration` or `yarn test:browser`
|
||||
2. Run `npm test:integration` or `npm test:browser`
|
||||
|
||||
When editing integration tests:
|
||||
* All imports should be from `xrpl-local` instead of `../../src` (browser tests need this)
|
||||
|
||||
65
test/integration/generateFaucetWallet.ts
Normal file
65
test/integration/generateFaucetWallet.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import assert from 'assert'
|
||||
|
||||
import _ from 'lodash'
|
||||
|
||||
import { Client, isValidClassicAddress, isValidXAddress } from 'xrpl-local'
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 60000
|
||||
// This test is reliant on external networks, and as such may be flaky.
|
||||
describe('generateFaucetWallet', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
it('submit generates a testnet wallet', async function () {
|
||||
const api = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
|
||||
await api.connect()
|
||||
const wallet = await api.generateFaucetWallet()
|
||||
|
||||
assert.notEqual(wallet, undefined)
|
||||
assert(isValidClassicAddress(wallet.classicAddress))
|
||||
assert(isValidXAddress(wallet.getXAddress()))
|
||||
|
||||
const info = await api.request({
|
||||
command: 'account_info',
|
||||
account: wallet.classicAddress,
|
||||
})
|
||||
assert.equal(info.result.account_data.Balance, '1000000000')
|
||||
|
||||
await api.generateFaucetWallet(wallet)
|
||||
|
||||
const afterSent = await api.request({
|
||||
command: 'account_info',
|
||||
account: wallet.classicAddress,
|
||||
})
|
||||
|
||||
assert.equal(afterSent.result.account_data.Balance, '2000000000')
|
||||
|
||||
await api.disconnect()
|
||||
})
|
||||
it('submit generates a devnet wallet', async function () {
|
||||
const api = new Client('wss://s.devnet.rippletest.net:51233')
|
||||
|
||||
await api.connect()
|
||||
const wallet = await api.generateFaucetWallet()
|
||||
|
||||
assert.notEqual(wallet, undefined)
|
||||
assert(isValidClassicAddress(wallet.classicAddress))
|
||||
assert(isValidXAddress(wallet.getXAddress()))
|
||||
|
||||
const info = await api.request({
|
||||
command: 'account_info',
|
||||
account: wallet.classicAddress,
|
||||
})
|
||||
assert.equal(info.result.account_data.Balance, '1000000000')
|
||||
|
||||
await api.generateFaucetWallet(wallet)
|
||||
|
||||
const afterSent = await api.request({
|
||||
command: 'account_info',
|
||||
account: wallet.classicAddress,
|
||||
})
|
||||
assert.equal(afterSent.result.account_data.Balance, '2000000000')
|
||||
|
||||
await api.disconnect()
|
||||
})
|
||||
})
|
||||
@@ -1,8 +1,41 @@
|
||||
/* eslint-disable import/export -- Tells webpack which files exist. */
|
||||
export * from './integration'
|
||||
export * from './transactions/signerListSet'
|
||||
export * from './transactions/payment'
|
||||
export * from './transactions/offerCreate'
|
||||
export * from './transactions/offerCancel'
|
||||
export * from './transactions/signerListSet'
|
||||
export * from './transactions/checkCancel'
|
||||
export * from './transactions/checkCash'
|
||||
export * from './transactions/checkCreate'
|
||||
export * from './transactions/depositPreauth'
|
||||
export * from './transactions/paymentChannelCreate'
|
||||
export * from './transactions/paymentChannelClaim'
|
||||
export * from './transactions/paymentChannelFund'
|
||||
export * from './transactions/trustSet'
|
||||
|
||||
export * from './requests/accountChannels'
|
||||
export * from './requests/accountCurrencies'
|
||||
export * from './requests/accountInfo'
|
||||
export * from './requests/accountLines'
|
||||
export * from './requests/accountObjects'
|
||||
export * from './requests/accountOffers'
|
||||
export * from './requests/accountTx'
|
||||
export * from './requests/bookOffers'
|
||||
export * from './requests/channelVerify'
|
||||
export * from './requests/depositAuthorized'
|
||||
export * from './requests/gatewayBalances'
|
||||
export * from './requests/ledger'
|
||||
export * from './requests/ledgerClosed'
|
||||
export * from './requests/ledgerCurrent'
|
||||
export * from './requests/ledgerData'
|
||||
export * from './requests/ledgerEntry'
|
||||
export * from './requests/multisign'
|
||||
export * from './requests/noRippleCheck'
|
||||
export * from './requests/pathFind'
|
||||
export * from './requests/ripplePathFind'
|
||||
export * from './requests/submit'
|
||||
export * from './requests/tx'
|
||||
export * from './requests/utility'
|
||||
|
||||
export * from './generateFaucetWallet'
|
||||
export * from './integration'
|
||||
|
||||
48
test/integration/requests/accountChannels.ts
Normal file
48
test/integration/requests/accountChannels.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { AccountChannelsRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_channels', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountChannelsRequest = {
|
||||
command: 'account_channels',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: this.wallet.getClassicAddress(),
|
||||
channels: [],
|
||||
ledger_hash:
|
||||
'C8BFA74A740AA22AD9BD724781589319052398B0C6C817B88D55628E07B7B4A1',
|
||||
ledger_index: 150,
|
||||
validated: true,
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
_.omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
})
|
||||
})
|
||||
49
test/integration/requests/accountCurrencies.ts
Normal file
49
test/integration/requests/accountCurrencies.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { AccountCurrenciesRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_currencies', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountCurrenciesRequest = {
|
||||
command: 'account_currencies',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
strict: true,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
receive_currencies: [],
|
||||
send_currencies: [],
|
||||
ledger_hash:
|
||||
'C8BFA74A740AA22AD9BD724781589319052398B0C6C817B88D55628E07B7B4A1',
|
||||
ledger_index: 150,
|
||||
validated: true,
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
_.omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
})
|
||||
})
|
||||
78
test/integration/requests/accountInfo.ts
Normal file
78
test/integration/requests/accountInfo.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { AccountInfoRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_info', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountInfoRequest = {
|
||||
command: 'account_info',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
strict: true,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account_data: {
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Balance: '400000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
OwnerCount: 0,
|
||||
PreviousTxnID:
|
||||
'19A8211695785A3A02C1C287D93C2B049E83A9CD609825E721052D63FF4F0EC8',
|
||||
PreviousTxnLgrSeq: 582,
|
||||
Sequence: 283,
|
||||
index:
|
||||
'BD4815E6EB304136E6044F778FB68D4E464CC8DFC59B8F6CC93D90A3709AE194',
|
||||
},
|
||||
ledger_hash:
|
||||
'F0DEEC46A7185BBB535517EE38CF2025973022D5B0532B36407F492521FDB0C6',
|
||||
ledger_index: 582,
|
||||
validated: true,
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(response.result.validated, expected.result.validated)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.equal(typeof response.result.account_data.PreviousTxnID, 'string')
|
||||
assert.equal(typeof response.result.account_data.index, 'string')
|
||||
assert.equal(
|
||||
typeof response.result.account_data.PreviousTxnLgrSeq,
|
||||
'number',
|
||||
)
|
||||
assert.equal(typeof response.result.account_data.Sequence, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result.account_data, [
|
||||
'PreviousTxnID',
|
||||
'PreviousTxnLgrSeq',
|
||||
'Sequence',
|
||||
'index',
|
||||
]),
|
||||
_.omit(expected.result.account_data, [
|
||||
'PreviousTxnID',
|
||||
'PreviousTxnLgrSeq',
|
||||
'Sequence',
|
||||
'index',
|
||||
]),
|
||||
)
|
||||
})
|
||||
})
|
||||
49
test/integration/requests/accountLines.ts
Normal file
49
test/integration/requests/accountLines.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { AccountLinesRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_lines', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountLinesRequest = {
|
||||
command: 'account_lines',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
strict: true,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: this.wallet.getClassicAddress(),
|
||||
ledger_hash:
|
||||
'0C09AAFA88AC1A616058220CF33269788D3985DAA6F2386196D4A7404252BB61',
|
||||
ledger_index: 1074,
|
||||
lines: [],
|
||||
validated: true,
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
_.omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
})
|
||||
})
|
||||
48
test/integration/requests/accountObjects.ts
Normal file
48
test/integration/requests/accountObjects.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { AccountObjectsRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_objects', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountObjectsRequest = {
|
||||
command: 'account_objects',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: this.wallet.getClassicAddress(),
|
||||
account_objects: [],
|
||||
ledger_hash:
|
||||
'28D68B351ED58B9819502EF5FC05BA4412A048597E5159E1C226703BDF7C7897',
|
||||
ledger_index: 1294,
|
||||
validated: true,
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
_.omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
})
|
||||
})
|
||||
45
test/integration/requests/accountOffers.ts
Normal file
45
test/integration/requests/accountOffers.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { AccountOffersRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_offers', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountOffersRequest = {
|
||||
command: 'account_offers',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
strict: true,
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: this.wallet.getClassicAddress(),
|
||||
ledger_current_index: 1443,
|
||||
offers: [],
|
||||
validated: false,
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_current_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, 'ledger_current_index'),
|
||||
_.omit(expected.result, 'ledger_current_index'),
|
||||
)
|
||||
})
|
||||
})
|
||||
103
test/integration/requests/accountTx.ts
Normal file
103
test/integration/requests/accountTx.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { AccountTxRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_tx', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountTxRequest = {
|
||||
command: 'account_tx',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
result: {
|
||||
account: this.wallet.getClassicAddress(),
|
||||
limit: 400,
|
||||
transactions: [
|
||||
{
|
||||
tx: {
|
||||
Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
Amount: '400000000',
|
||||
Destination: this.wallet.getClassicAddress(),
|
||||
Fee: '12',
|
||||
Flags: 0,
|
||||
LastLedgerSequence: 1753,
|
||||
Sequence: 843,
|
||||
SigningPubKey:
|
||||
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020',
|
||||
TransactionType: 'Payment',
|
||||
TxnSignature:
|
||||
'30440220693D244BC13967E3DA67BDC974096784ED03DD4ACE6F36645E5176988452AFCF02200F8AB172432913899F27EC5523829AEDAD00CC2445690400E294EDF652A85945',
|
||||
date: 685747005,
|
||||
hash: '2E68BC15813B4A836FAC4D80E42E6FDA6410E99AB973937DEA5E6C2E9A116BAB',
|
||||
inLedger: 1734,
|
||||
ledger_index: 1734,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(response.result.account, expected.result.account)
|
||||
assert.equal(
|
||||
response.result.transactions[0].meta.TransactionResult,
|
||||
'tesSUCCESS',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx.LastLedgerSequence,
|
||||
'number',
|
||||
)
|
||||
assert.equal(typeof response.result.transactions[0].tx.Sequence, 'number')
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx.SigningPubKey,
|
||||
'string',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx.TxnSignature,
|
||||
'string',
|
||||
)
|
||||
assert.equal(typeof response.result.transactions[0].tx.Fee, 'string')
|
||||
assert.equal(typeof response.result.transactions[0].tx.hash, 'string')
|
||||
assert.equal(typeof response.result.transactions[0].tx.inLedger, 'number')
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx.ledger_index,
|
||||
'number',
|
||||
)
|
||||
|
||||
const responseTx = response.result.transactions[0].tx
|
||||
const expectedTx = expected.result.transactions[0].tx
|
||||
assert.deepEqual(
|
||||
[
|
||||
responseTx.Flags,
|
||||
responseTx.TransactionType,
|
||||
responseTx.Account,
|
||||
responseTx.Amount,
|
||||
responseTx.Destination,
|
||||
],
|
||||
[
|
||||
expectedTx.Flags,
|
||||
expectedTx.TransactionType,
|
||||
expectedTx.Account,
|
||||
expectedTx.Amount,
|
||||
expectedTx.Destination,
|
||||
],
|
||||
)
|
||||
})
|
||||
})
|
||||
45
test/integration/requests/bookOffers.ts
Normal file
45
test/integration/requests/bookOffers.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { BookOffersRequest, BookOffersResponse } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('book_offers', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const bookOffer: BookOffersRequest = {
|
||||
command: 'book_offers',
|
||||
taker_gets: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
taker_pays: {
|
||||
currency: 'USD',
|
||||
issuer: this.wallet.getClassicAddress(),
|
||||
},
|
||||
}
|
||||
const response = await this.client.request(bookOffer)
|
||||
|
||||
const expectedResponse: BookOffersResponse = {
|
||||
id: response.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_current_index: response.result.ledger_current_index,
|
||||
offers: response.result.offers,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
})
|
||||
})
|
||||
43
test/integration/requests/channelVerify.ts
Normal file
43
test/integration/requests/channelVerify.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { ChannelVerifyRequest, ChannelVerifyResponse } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('channel_verify', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const channelVerify: ChannelVerifyRequest = {
|
||||
command: 'channel_verify',
|
||||
channel_id:
|
||||
'5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3',
|
||||
signature:
|
||||
'304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064',
|
||||
public_key: 'aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3',
|
||||
amount: '1000000',
|
||||
}
|
||||
|
||||
const response = await this.client.request(channelVerify)
|
||||
|
||||
const expectedResponse: ChannelVerifyResponse = {
|
||||
id: response.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
signature_verified: response.result.signature_verified,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
})
|
||||
})
|
||||
45
test/integration/requests/depositAuthorized.ts
Normal file
45
test/integration/requests/depositAuthorized.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { DepositAuthorizedRequest, DepositAuthorizedResponse } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('deposit_authorized', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const depositAuthorized: DepositAuthorizedRequest = {
|
||||
command: 'deposit_authorized',
|
||||
source_account: this.wallet.getClassicAddress(),
|
||||
destination_account: wallet2.getClassicAddress(),
|
||||
}
|
||||
|
||||
const response = await this.client.request(depositAuthorized)
|
||||
|
||||
const expectedResponse: DepositAuthorizedResponse = {
|
||||
id: response.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
deposit_authorized: true,
|
||||
destination_account: depositAuthorized.destination_account,
|
||||
ledger_current_index: response.result.ledger_current_index,
|
||||
source_account: depositAuthorized.source_account,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
})
|
||||
})
|
||||
56
test/integration/requests/fee.ts
Normal file
56
test/integration/requests/fee.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { FeeRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('fee', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: FeeRequest = {
|
||||
command: 'fee',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
current_ledger_size: '0',
|
||||
current_queue_size: '0',
|
||||
drops: {
|
||||
base_fee: '10',
|
||||
median_fee: '5000',
|
||||
minimum_fee: '10',
|
||||
open_ledger_fee: '10',
|
||||
},
|
||||
expected_ledger_size: '1000',
|
||||
ledger_current_index: 2925,
|
||||
levels: {
|
||||
median_level: '128000',
|
||||
minimum_level: '256',
|
||||
open_ledger_level: '256',
|
||||
reference_level: '256',
|
||||
},
|
||||
max_queue_size: '20000',
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_current_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_current_index']),
|
||||
_.omit(expected.result, ['ledger_current_index']),
|
||||
)
|
||||
})
|
||||
})
|
||||
48
test/integration/requests/gatewayBalances.ts
Normal file
48
test/integration/requests/gatewayBalances.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { GatewayBalancesRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('gateway_balances', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: GatewayBalancesRequest = {
|
||||
command: 'gateway_balances',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
ledger_index: 'validated',
|
||||
strict: true,
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: this.wallet.getClassicAddress(),
|
||||
ledger_hash:
|
||||
'28D68B351ED58B9819502EF5FC05BA4412A048597E5159E1C226703BDF7C7897',
|
||||
ledger_index: 1294,
|
||||
validated: true,
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
_.omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
})
|
||||
})
|
||||
31
test/integration/requests/ledger.ts
Normal file
31
test/integration/requests/ledger.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { LedgerRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { verifySuccessfulResponse } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ledger', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const ledgerRequest: LedgerRequest = {
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
|
||||
const ledgerResponse = await this.client.request(ledgerRequest)
|
||||
|
||||
verifySuccessfulResponse(ledgerResponse)
|
||||
assert(ledgerResponse.result.validated)
|
||||
})
|
||||
})
|
||||
40
test/integration/requests/ledgerClosed.ts
Normal file
40
test/integration/requests/ledgerClosed.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { LedgerClosedRequest, LedgerClosedResponse } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { verifySuccessfulResponse } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ledger_closed', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const ledgerClosedRequest: LedgerClosedRequest = {
|
||||
command: 'ledger_closed',
|
||||
}
|
||||
const ledgerClosedResponse: LedgerClosedResponse =
|
||||
await this.client.request(ledgerClosedRequest)
|
||||
|
||||
verifySuccessfulResponse(ledgerClosedResponse)
|
||||
|
||||
const expectedResponse: LedgerClosedResponse = {
|
||||
id: ledgerClosedResponse.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_hash: ledgerClosedResponse.result.ledger_hash,
|
||||
ledger_index: ledgerClosedResponse.result.ledger_index,
|
||||
},
|
||||
}
|
||||
assert.deepEqual(ledgerClosedResponse, expectedResponse)
|
||||
})
|
||||
})
|
||||
41
test/integration/requests/ledgerCurrent.ts
Normal file
41
test/integration/requests/ledgerCurrent.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { LedgerCurrentResponse, LedgerCurrentRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { verifySuccessfulResponse } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ledger_current', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const ledgerCurrentRequest: LedgerCurrentRequest = {
|
||||
command: 'ledger_current',
|
||||
}
|
||||
|
||||
const ledgerCurrentResponse = await this.client.request(
|
||||
ledgerCurrentRequest,
|
||||
)
|
||||
|
||||
verifySuccessfulResponse(ledgerCurrentResponse)
|
||||
|
||||
const expectedResponse: LedgerCurrentResponse = {
|
||||
id: ledgerCurrentResponse.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_current_index: ledgerCurrentResponse.result.ledger_current_index,
|
||||
},
|
||||
}
|
||||
assert.deepEqual(ledgerCurrentResponse, expectedResponse)
|
||||
})
|
||||
})
|
||||
35
test/integration/requests/ledgerData.ts
Normal file
35
test/integration/requests/ledgerData.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { LedgerDataRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { verifySuccessfulResponse } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ledger_data', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const ledgerDataRequest: LedgerDataRequest = {
|
||||
command: 'ledger_data',
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
|
||||
const ledgerDataResponse = await this.client.request(ledgerDataRequest)
|
||||
|
||||
verifySuccessfulResponse(ledgerDataResponse)
|
||||
|
||||
assert.equal(ledgerDataResponse.result.validated, true)
|
||||
assert(ledgerDataResponse.result.state.length > 0)
|
||||
assert.equal(ledgerDataResponse.status, 'success')
|
||||
assert.equal(ledgerDataResponse.type, 'response')
|
||||
})
|
||||
})
|
||||
51
test/integration/requests/ledgerEntry.ts
Normal file
51
test/integration/requests/ledgerEntry.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { LedgerEntryRequest, LedgerEntryResponse } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { verifySuccessfulResponse } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ledger_entry', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const validatedLedgerResponse = await this.client.request({
|
||||
command: 'ledger_data',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
|
||||
verifySuccessfulResponse(validatedLedgerResponse)
|
||||
const ledgerEntryIndex = validatedLedgerResponse.result.state[0].index
|
||||
|
||||
const ledgerEntryRequest: LedgerEntryRequest = {
|
||||
command: 'ledger_entry',
|
||||
index: ledgerEntryIndex,
|
||||
}
|
||||
|
||||
const ledgerEntryResponse = await this.client.request(ledgerEntryRequest)
|
||||
|
||||
const expectedResponse: LedgerEntryResponse = {
|
||||
id: ledgerEntryResponse.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
index: ledgerEntryIndex,
|
||||
ledger_current_index: ledgerEntryResponse.result.ledger_current_index,
|
||||
node: ledgerEntryResponse.result.node,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
verifySuccessfulResponse(ledgerEntryResponse)
|
||||
assert.deepEqual(ledgerEntryResponse, expectedResponse)
|
||||
})
|
||||
})
|
||||
101
test/integration/requests/multisign.ts
Normal file
101
test/integration/requests/multisign.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { decode } from 'ripple-binary-codec/dist'
|
||||
|
||||
import {
|
||||
AccountSet,
|
||||
Client,
|
||||
SignerListSet,
|
||||
SubmitMultisignedRequest,
|
||||
Transaction,
|
||||
SubmitMultisignedResponse,
|
||||
computeSignedTransactionHash,
|
||||
} from 'xrpl-local'
|
||||
import { convertStringToHex } from 'xrpl-local/utils'
|
||||
import { multisign, sign } from 'xrpl-local/wallet/signer'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import {
|
||||
generateFundedWallet,
|
||||
ledgerAccept,
|
||||
testTransaction,
|
||||
verifySubmittedTransaction,
|
||||
} from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('submit_multisigned', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('submit_multisigned transaction', async function () {
|
||||
const client: Client = this.client
|
||||
const signerWallet1 = await generateFundedWallet(this.client)
|
||||
const signerWallet2 = await generateFundedWallet(this.client)
|
||||
|
||||
// set up the multisigners for the account
|
||||
const signerListSet: SignerListSet = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
SignerEntries: [
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet1.getClassicAddress(),
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet2.getClassicAddress(),
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
SignerQuorum: 2,
|
||||
}
|
||||
await testTransaction(this.client, signerListSet, this.wallet)
|
||||
|
||||
// try to multisign
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const accountSetTx = await client.autofill(accountSet, 2)
|
||||
const signed1 = sign(signerWallet1, accountSetTx, true)
|
||||
const signed2 = sign(signerWallet2, accountSetTx, true)
|
||||
const multisigned = multisign([signed1, signed2])
|
||||
const multisignedRequest: SubmitMultisignedRequest = {
|
||||
command: 'submit_multisigned',
|
||||
tx_json: decode(multisigned) as unknown as Transaction,
|
||||
}
|
||||
const submitResponse = await client.request(multisignedRequest)
|
||||
await ledgerAccept(client)
|
||||
assert.strictEqual(submitResponse.result.engine_result, 'tesSUCCESS')
|
||||
await verifySubmittedTransaction(this.client, multisigned)
|
||||
|
||||
const expectedResponse: SubmitMultisignedResponse = {
|
||||
id: submitResponse.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
engine_result: 'tesSUCCESS',
|
||||
engine_result_code: 0,
|
||||
engine_result_message:
|
||||
'The transaction was applied. Only final in a validated ledger.',
|
||||
tx_blob: multisigned,
|
||||
tx_json: {
|
||||
...(decode(multisigned) as unknown as Transaction),
|
||||
hash: computeSignedTransactionHash(multisigned),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(submitResponse, expectedResponse)
|
||||
})
|
||||
})
|
||||
61
test/integration/requests/noRippleCheck.ts
Normal file
61
test/integration/requests/noRippleCheck.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { NoRippleCheckRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('noripple_check', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: NoRippleCheckRequest = {
|
||||
command: 'noripple_check',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
role: 'gateway',
|
||||
ledger_index: 'current',
|
||||
transactions: true,
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
ledger_current_index: 2535,
|
||||
problems: ['You should immediately set your default ripple flag'],
|
||||
transactions: [
|
||||
{
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Fee: 10,
|
||||
Sequence: 1268,
|
||||
SetFlag: 8,
|
||||
TransactionType: 'AccountSet',
|
||||
},
|
||||
],
|
||||
validated: false,
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.transactions[0].Fee, 'number')
|
||||
assert.equal(typeof response.result.transactions[0].Sequence, 'number')
|
||||
assert.equal(typeof response.result.problems, 'object')
|
||||
assert.equal(typeof response.result.problems[0], 'string')
|
||||
|
||||
const responseTx = response.result.transactions[0]
|
||||
const expectedTx = expected.result.transactions[0]
|
||||
assert.deepEqual(
|
||||
[responseTx.Account, responseTx.SetFlag, responseTx.TransactionType],
|
||||
[expectedTx.Account, expectedTx.SetFlag, expectedTx.TransactionType],
|
||||
)
|
||||
})
|
||||
})
|
||||
48
test/integration/requests/pathFind.ts
Normal file
48
test/integration/requests/pathFind.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { PathFindRequest, PathFindResponse } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('path_find', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const pathFind: PathFindRequest = {
|
||||
command: 'path_find',
|
||||
subcommand: 'create',
|
||||
source_account: this.wallet.getClassicAddress(),
|
||||
destination_account: wallet2.getClassicAddress(),
|
||||
destination_amount: '100',
|
||||
}
|
||||
|
||||
const response = await this.client.request(pathFind)
|
||||
|
||||
const expectedResponse: PathFindResponse = {
|
||||
id: response.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
alternatives: response.result.alternatives,
|
||||
destination_account: pathFind.destination_account,
|
||||
destination_amount: pathFind.destination_amount,
|
||||
source_account: pathFind.source_account,
|
||||
full_reply: false,
|
||||
id: response.id,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
})
|
||||
})
|
||||
51
test/integration/requests/ripplePathFind.ts
Normal file
51
test/integration/requests/ripplePathFind.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { RipplePathFindRequest, RipplePathFindResponse } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ripple_path_find', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const ripplePathFind: RipplePathFindRequest = {
|
||||
command: 'ripple_path_find',
|
||||
subcommand: 'create',
|
||||
source_account: this.wallet.getClassicAddress(),
|
||||
destination_account: wallet2.getClassicAddress(),
|
||||
destination_amount: '100',
|
||||
}
|
||||
|
||||
const response = await this.client.request(ripplePathFind)
|
||||
|
||||
const expectedResponse: RipplePathFindResponse = {
|
||||
id: response.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
alternatives: response.result.alternatives,
|
||||
destination_account: wallet2.getClassicAddress(),
|
||||
destination_currencies: response.result.destination_currencies,
|
||||
destination_amount: ripplePathFind.destination_amount,
|
||||
full_reply: true,
|
||||
id: response.id,
|
||||
ledger_current_index: response.result.ledger_current_index,
|
||||
source_account: ripplePathFind.source_account,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
})
|
||||
})
|
||||
136
test/integration/requests/serverInfo.ts
Normal file
136
test/integration/requests/serverInfo.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { ServerInfoRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('server_info', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: ServerInfoRequest = {
|
||||
command: 'server_info',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
info: {
|
||||
build_version: '1.7.3',
|
||||
complete_ledgers: '2563-2928',
|
||||
hostid: '44578fe64241',
|
||||
io_latency_ms: 1,
|
||||
jq_trans_overflow: '0',
|
||||
last_close: { converge_time_s: 0.1, proposers: 0 },
|
||||
load: {
|
||||
job_types: [
|
||||
{
|
||||
in_progress: 1,
|
||||
job_type: 'clientCommand',
|
||||
peak_time: 4,
|
||||
per_second: 9,
|
||||
},
|
||||
{ job_type: 'updatePaths', per_second: 1 },
|
||||
{ job_type: 'advanceLedger', per_second: 1 },
|
||||
{ job_type: 'pathFind', per_second: 1 },
|
||||
{ job_type: 'WriteNode', per_second: 17 },
|
||||
],
|
||||
threads: 1,
|
||||
},
|
||||
load_factor: 1,
|
||||
peer_disconnects: '0',
|
||||
peer_disconnects_resources: '0',
|
||||
peers: 0,
|
||||
pubkey_node: 'n9K6DaaReKkCjb9sEfXh5xP3BV9JisrJ9biKB3CSSFXancBnv5cW',
|
||||
pubkey_validator: 'none',
|
||||
server_state: 'full',
|
||||
server_state_duration_us: '8752395105',
|
||||
state_accounting: {
|
||||
connected: { duration_us: '0', transitions: 0 },
|
||||
disconnected: { duration_us: '41860', transitions: 1 },
|
||||
full: { duration_us: '20723121268', transitions: 1 },
|
||||
syncing: { duration_us: '0', transitions: 0 },
|
||||
tracking: { duration_us: '0', transitions: 0 },
|
||||
},
|
||||
time: '2021-Sep-23 22:56:55.320858 UTC',
|
||||
uptime: 8752,
|
||||
validated_ledger: {
|
||||
age: 0,
|
||||
base_fee_xrp: 0.00001,
|
||||
hash: '532175EC25CF34081D7F83584F37DAB70035A422CBE94352BEDA8EC123CB8F60',
|
||||
reserve_base_xrp: 200,
|
||||
reserve_inc_xrp: 50,
|
||||
seq: 1906,
|
||||
},
|
||||
validation_quorum: 0,
|
||||
validator_list: {
|
||||
count: 0,
|
||||
expiration: 'unknown',
|
||||
status: 'unknown',
|
||||
},
|
||||
},
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
|
||||
assert.equal(typeof response.result.info.time, 'string')
|
||||
assert.equal(typeof response.result.info.uptime, 'number')
|
||||
assert.equal(typeof response.result.info.complete_ledgers, 'string')
|
||||
assert.equal(typeof response.result.info.hostid, 'string')
|
||||
assert.equal(typeof response.result.info.pubkey_node, 'string')
|
||||
assert.equal(typeof response.result.info.server_state_duration_us, 'string')
|
||||
const removeKeys = [
|
||||
'time',
|
||||
'uptime',
|
||||
'complete_ledgers',
|
||||
'hostid',
|
||||
'load',
|
||||
'state_accounting',
|
||||
'pubkey_node',
|
||||
'server_state_duration_us',
|
||||
'validated_ledger',
|
||||
]
|
||||
assert.deepEqual(
|
||||
_.omit(response.result.info, removeKeys),
|
||||
_.omit(expected.result.info, removeKeys),
|
||||
)
|
||||
|
||||
// load
|
||||
assert.equal(typeof response.result.info.load.threads, 'number')
|
||||
for (const obj of response.result.info.load.job_types) {
|
||||
assert.equal(typeof obj.per_second, 'number')
|
||||
assert.equal(typeof obj.job_type, 'string')
|
||||
}
|
||||
// state_accounting
|
||||
Object.keys(response.result.info.state_accounting).forEach(function (key) {
|
||||
assert.equal(
|
||||
typeof response.result.info.state_accounting[key].duration_us,
|
||||
'string',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.info.state_accounting[key].transitions,
|
||||
'number',
|
||||
)
|
||||
})
|
||||
|
||||
// validated_ledger
|
||||
assert.equal(typeof response.result.info.validated_ledger.hash, 'string')
|
||||
for (const key of Object.keys(
|
||||
_.omit(response.result.info.validated_ledger, 'hash'),
|
||||
)) {
|
||||
assert.equal(typeof response.result.info.validated_ledger[key], 'number')
|
||||
}
|
||||
})
|
||||
})
|
||||
141
test/integration/requests/serverState.ts
Normal file
141
test/integration/requests/serverState.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { ServerStateRequest } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('server_state', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: ServerStateRequest = {
|
||||
command: 'server_state',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
state: {
|
||||
build_version: '1.7.3',
|
||||
complete_ledgers: '2563-2932',
|
||||
io_latency_ms: 1,
|
||||
jq_trans_overflow: '0',
|
||||
last_close: {
|
||||
converge_time: 100,
|
||||
proposers: 0,
|
||||
},
|
||||
load: {
|
||||
job_types: [
|
||||
{
|
||||
in_progress: 1,
|
||||
job_type: 'clientCommand',
|
||||
peak_time: 4,
|
||||
per_second: 9,
|
||||
},
|
||||
{ job_type: 'updatePaths', per_second: 1 },
|
||||
{ job_type: 'advanceLedger', per_second: 1 },
|
||||
{ job_type: 'pathFind', per_second: 1 },
|
||||
{ job_type: 'WriteNode', per_second: 17 },
|
||||
],
|
||||
threads: 1,
|
||||
},
|
||||
load_base: 256,
|
||||
load_factor: 256,
|
||||
load_factor_fee_escalation: 256,
|
||||
load_factor_fee_queue: 256,
|
||||
load_factor_fee_reference: 256,
|
||||
load_factor_server: 256,
|
||||
peer_disconnects: '0',
|
||||
peer_disconnects_resources: '0',
|
||||
peers: 0,
|
||||
pubkey_node: 'n9K6DaaReKkCjb9sEfXh5xP3BV9JisrJ9biKB3CSSFXancBnv5cW',
|
||||
pubkey_validator: 'none',
|
||||
server_state: 'full',
|
||||
server_state_duration_us: '8752487389',
|
||||
state_accounting: {
|
||||
connected: { duration_us: '0', transitions: 0 },
|
||||
disconnected: { duration_us: '41860', transitions: 1 },
|
||||
full: { duration_us: '20723121268', transitions: 1 },
|
||||
syncing: { duration_us: '0', transitions: 0 },
|
||||
tracking: { duration_us: '0', transitions: 0 },
|
||||
},
|
||||
time: '2021-Sep-23 22:56:55.413151 UTC',
|
||||
uptime: 8752,
|
||||
validated_ledger: {
|
||||
base_fee: 10,
|
||||
close_time: 685829741,
|
||||
hash: 'B98AABCE40A54DF654C86E56088AD7D46BBA8B8E93AD3FAC2426FEFF847F7937',
|
||||
reserve_base: 200000000,
|
||||
reserve_inc: 50000000,
|
||||
seq: 2294,
|
||||
},
|
||||
validation_quorum: 0,
|
||||
validator_list_expires: 0,
|
||||
},
|
||||
},
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.status, expected.status)
|
||||
assert.equal(response.type, expected.type)
|
||||
|
||||
assert.equal(typeof response.result.state.complete_ledgers, 'string')
|
||||
assert.equal(typeof response.result.state.pubkey_node, 'string')
|
||||
assert.equal(typeof response.result.state.time, 'string')
|
||||
assert.equal(typeof response.result.state.uptime, 'number')
|
||||
assert.equal(
|
||||
typeof response.result.state.server_state_duration_us,
|
||||
'string',
|
||||
)
|
||||
|
||||
const removeKeys = [
|
||||
'complete_ledgers',
|
||||
'load',
|
||||
'state_accounting',
|
||||
'pubkey_node',
|
||||
'time',
|
||||
'uptime',
|
||||
'server_state_duration_us',
|
||||
'validated_ledger',
|
||||
]
|
||||
assert.deepEqual(
|
||||
_.omit(response.result.state, removeKeys),
|
||||
_.omit(expected.result.state, removeKeys),
|
||||
)
|
||||
|
||||
// load
|
||||
assert.equal(typeof response.result.state.load.threads, 'number')
|
||||
for (const obj of response.result.state.load.job_types) {
|
||||
assert.equal(typeof obj.per_second, 'number')
|
||||
assert.equal(typeof obj.job_type, 'string')
|
||||
}
|
||||
// state_accounting
|
||||
Object.keys(response.result.state.state_accounting).forEach(function (key) {
|
||||
assert.equal(
|
||||
typeof response.result.state.state_accounting[key].duration_us,
|
||||
'string',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.state.state_accounting[key].transitions,
|
||||
'number',
|
||||
)
|
||||
})
|
||||
|
||||
// validated_ledger
|
||||
assert.equal(typeof response.result.state.validated_ledger.hash, 'string')
|
||||
for (const key of Object.keys(
|
||||
_.omit(response.result.state.validated_ledger, 'hash'),
|
||||
)) {
|
||||
assert.equal(typeof response.result.state.validated_ledger[key], 'number')
|
||||
}
|
||||
})
|
||||
})
|
||||
76
test/integration/requests/submit.ts
Normal file
76
test/integration/requests/submit.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { decode } from 'ripple-binary-codec/dist'
|
||||
|
||||
import {
|
||||
AccountSet,
|
||||
SubmitRequest,
|
||||
SubmitResponse,
|
||||
computeSignedTransactionHash,
|
||||
Transaction,
|
||||
} from 'xrpl-local'
|
||||
import { convertStringToHex } from 'xrpl-local/utils'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { ledgerAccept, verifySubmittedTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('submit', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('submit', async function () {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
const autofilledTx = await this.client.autofill(accountSet)
|
||||
const signedTx = this.wallet.signTransaction(autofilledTx)
|
||||
const submitRequest: SubmitRequest = {
|
||||
command: 'submit',
|
||||
tx_blob: signedTx,
|
||||
}
|
||||
const submitResponse = await this.client.request(submitRequest)
|
||||
assert.equal(submitResponse.status, 'success')
|
||||
|
||||
await ledgerAccept(this.client)
|
||||
await verifySubmittedTransaction(this.client, signedTx)
|
||||
|
||||
const expectedResponse: SubmitResponse = {
|
||||
id: submitResponse.id,
|
||||
type: 'response',
|
||||
status: 'success',
|
||||
result: {
|
||||
engine_result: 'tesSUCCESS',
|
||||
engine_result_code: 0,
|
||||
engine_result_message:
|
||||
'The transaction was applied. Only final in a validated ledger.',
|
||||
tx_blob: signedTx,
|
||||
tx_json: {
|
||||
...(decode(signedTx) as unknown as Transaction),
|
||||
hash: computeSignedTransactionHash(signedTx),
|
||||
},
|
||||
accepted: true,
|
||||
account_sequence_available:
|
||||
submitResponse.result.account_sequence_available,
|
||||
account_sequence_next: submitResponse.result.account_sequence_next,
|
||||
applied: true,
|
||||
broadcast: submitResponse.result.broadcast,
|
||||
kept: true,
|
||||
queued: false,
|
||||
open_ledger_cost: submitResponse.result.open_ledger_cost,
|
||||
validated_ledger_index: submitResponse.result.validated_ledger_index,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(submitResponse, expectedResponse)
|
||||
})
|
||||
})
|
||||
63
test/integration/requests/tx.ts
Normal file
63
test/integration/requests/tx.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import {
|
||||
AccountSet,
|
||||
computeSignedTransactionHash,
|
||||
SubmitResponse,
|
||||
TxResponse,
|
||||
} from 'xrpl-local'
|
||||
import { convertStringToHex } from 'xrpl-local/utils'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('tx', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const account = this.wallet.getClassicAddress()
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: account,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
const response: SubmitResponse = await this.client.submitTransaction(
|
||||
this.wallet,
|
||||
accountSet,
|
||||
)
|
||||
|
||||
const hash = computeSignedTransactionHash(response.result.tx_blob)
|
||||
const txResponse = await this.client.request({
|
||||
command: 'tx',
|
||||
transaction: hash,
|
||||
})
|
||||
|
||||
const expectedResponse: TxResponse = {
|
||||
id: txResponse.id,
|
||||
type: 'response',
|
||||
status: 'success',
|
||||
result: {
|
||||
...accountSet,
|
||||
Fee: txResponse.result.Fee,
|
||||
Flags: 0,
|
||||
LastLedgerSequence: txResponse.result.LastLedgerSequence,
|
||||
Sequence: txResponse.result.Sequence,
|
||||
SigningPubKey: this.wallet.publicKey,
|
||||
TxnSignature: txResponse.result.TxnSignature,
|
||||
hash: computeSignedTransactionHash(response.result.tx_blob),
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(txResponse, expectedResponse)
|
||||
})
|
||||
})
|
||||
@@ -13,15 +13,6 @@ export async function suiteClientSetup(this: Mocha.Context): Promise<void> {
|
||||
await setupClient.bind(this)(serverUrl)
|
||||
await ledgerAccept(this.client)
|
||||
this.newWallet = generateXAddress({ includeClassicAddress: true })
|
||||
// two times to give time to server to send `ledgerClosed` event
|
||||
// so getLedgerVersion will return right value
|
||||
await ledgerAccept(this.client)
|
||||
const response = await this.client.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
const ledgerVersion = response.result.ledger_index
|
||||
this.startLedgerVersion = ledgerVersion
|
||||
await teardownClient.bind(this)()
|
||||
}
|
||||
|
||||
|
||||
35
test/integration/transactions/accountDelete.ts
Normal file
35
test/integration/transactions/accountDelete.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
import { AccountDelete } from 'xrpl-local/models/transactions'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet, ledgerAccept, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('AccountDelete', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
// to the satisfy the condition that account sequence and current ledger_index should be 256 apart.
|
||||
const promises: Array<Promise<void>> = []
|
||||
for (let iter = 0; iter < 256; iter += 1) {
|
||||
promises.push(ledgerAccept(this.client))
|
||||
}
|
||||
|
||||
await Promise.all(promises)
|
||||
const tx: AccountDelete = {
|
||||
TransactionType: 'AccountDelete',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Destination: wallet2.getClassicAddress(),
|
||||
}
|
||||
await testTransaction(this.client, tx, this.wallet)
|
||||
})
|
||||
})
|
||||
26
test/integration/transactions/accountSet.ts
Normal file
26
test/integration/transactions/accountSet.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
import { AccountSet } from 'xrpl-local/models/transactions'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('AccountSet', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const tx: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
}
|
||||
await testTransaction(this.client, tx, this.wallet)
|
||||
})
|
||||
})
|
||||
65
test/integration/transactions/checkCancel.ts
Normal file
65
test/integration/transactions/checkCancel.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { CheckCreate, CheckCancel } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('CheckCancel', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const setupTx: CheckCreate = {
|
||||
TransactionType: 'CheckCreate',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Destination: wallet2.getClassicAddress(),
|
||||
SendMax: '50',
|
||||
}
|
||||
|
||||
await testTransaction(this.client, setupTx, this.wallet)
|
||||
|
||||
// get check ID
|
||||
const response1 = await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
response1.result.account_objects,
|
||||
1,
|
||||
'Should be exactly one check on the ledger',
|
||||
)
|
||||
const checkId = response1.result.account_objects[0].index
|
||||
|
||||
// actual test - cancel the check
|
||||
const tx: CheckCancel = {
|
||||
TransactionType: 'CheckCancel',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
CheckID: checkId,
|
||||
}
|
||||
|
||||
await testTransaction(this.client, tx, this.wallet)
|
||||
|
||||
// confirm that the check no longer exists
|
||||
const accountOffersResponse = await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
accountOffersResponse.result.account_objects,
|
||||
0,
|
||||
'Should be no checks on the ledger',
|
||||
)
|
||||
})
|
||||
})
|
||||
68
test/integration/transactions/checkCash.ts
Normal file
68
test/integration/transactions/checkCash.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { CheckCreate, CheckCash } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('CheckCash', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const amount = '500'
|
||||
|
||||
const setupTx: CheckCreate = {
|
||||
TransactionType: 'CheckCreate',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Destination: wallet2.getClassicAddress(),
|
||||
SendMax: amount,
|
||||
}
|
||||
|
||||
await testTransaction(this.client, setupTx, this.wallet)
|
||||
|
||||
// get check ID
|
||||
const response1 = await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
response1.result.account_objects,
|
||||
1,
|
||||
'Should be exactly one check on the ledger',
|
||||
)
|
||||
const checkId = response1.result.account_objects[0].index
|
||||
|
||||
// actual test - cash the check
|
||||
const tx: CheckCash = {
|
||||
TransactionType: 'CheckCash',
|
||||
Account: wallet2.getClassicAddress(),
|
||||
CheckID: checkId,
|
||||
Amount: amount,
|
||||
}
|
||||
|
||||
await testTransaction(this.client, tx, wallet2)
|
||||
|
||||
// confirm that the check no longer exists
|
||||
const accountOffersResponse = await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
accountOffersResponse.result.account_objects,
|
||||
0,
|
||||
'Should be no checks on the ledger',
|
||||
)
|
||||
})
|
||||
})
|
||||
43
test/integration/transactions/checkCreate.ts
Normal file
43
test/integration/transactions/checkCreate.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { CheckCreate } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('CheckCreate', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const tx: CheckCreate = {
|
||||
TransactionType: 'CheckCreate',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Destination: wallet2.getClassicAddress(),
|
||||
SendMax: '50',
|
||||
}
|
||||
|
||||
await testTransaction(this.client, tx, this.wallet)
|
||||
|
||||
// confirm that the check actually went through
|
||||
const accountOffersResponse = await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.getClassicAddress(),
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
accountOffersResponse.result.account_objects,
|
||||
1,
|
||||
'Should be exactly one check on the ledger',
|
||||
)
|
||||
})
|
||||
})
|
||||
54
test/integration/transactions/paymentChannelClaim.ts
Normal file
54
test/integration/transactions/paymentChannelClaim.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
import {
|
||||
PaymentChannelCreate,
|
||||
computePaymentChannelHash,
|
||||
PaymentChannelClaim,
|
||||
} from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('PaymentChannelClaim', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const paymentChannelCreate: PaymentChannelCreate = {
|
||||
TransactionType: 'PaymentChannelCreate',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Amount: '100',
|
||||
Destination: wallet2.getClassicAddress(),
|
||||
SettleDelay: 86400,
|
||||
PublicKey: this.wallet.publicKey,
|
||||
}
|
||||
|
||||
const paymentChannelResponse = await this.client.submitTransaction(
|
||||
this.wallet,
|
||||
paymentChannelCreate,
|
||||
)
|
||||
|
||||
await testTransaction(this.client, paymentChannelCreate, this.wallet)
|
||||
|
||||
const paymentChannelClaim: PaymentChannelClaim = {
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
TransactionType: 'PaymentChannelClaim',
|
||||
Channel: computePaymentChannelHash(
|
||||
this.wallet.getClassicAddress(),
|
||||
wallet2.getClassicAddress(),
|
||||
paymentChannelResponse.result.tx_json.Sequence ?? 0,
|
||||
),
|
||||
Amount: '100',
|
||||
}
|
||||
|
||||
await testTransaction(this.client, paymentChannelClaim, this.wallet)
|
||||
})
|
||||
})
|
||||
32
test/integration/transactions/paymentChannelCreate.ts
Normal file
32
test/integration/transactions/paymentChannelCreate.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
import { PaymentChannelCreate } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('PaymentChannelCreate', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const paymentChannelCreate: PaymentChannelCreate = {
|
||||
TransactionType: 'PaymentChannelCreate',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Amount: '100',
|
||||
Destination: wallet2.getClassicAddress(),
|
||||
SettleDelay: 86400,
|
||||
PublicKey: this.wallet.publicKey,
|
||||
}
|
||||
|
||||
await testTransaction(this.client, paymentChannelCreate, this.wallet)
|
||||
})
|
||||
})
|
||||
53
test/integration/transactions/paymentChannelFund.ts
Normal file
53
test/integration/transactions/paymentChannelFund.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
import {
|
||||
PaymentChannelCreate,
|
||||
computePaymentChannelHash,
|
||||
PaymentChannelFund,
|
||||
} from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('PaymentChannelFund', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const paymentChannelCreate: PaymentChannelCreate = {
|
||||
TransactionType: 'PaymentChannelCreate',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
Amount: '100',
|
||||
Destination: wallet2.getClassicAddress(),
|
||||
SettleDelay: 86400,
|
||||
PublicKey: this.wallet.publicKey,
|
||||
}
|
||||
|
||||
const paymentChannelResponse = await this.client.submitTransaction(
|
||||
this.wallet,
|
||||
paymentChannelCreate,
|
||||
)
|
||||
await testTransaction(this.client, paymentChannelCreate, this.wallet)
|
||||
|
||||
const paymentChannelFund: PaymentChannelFund = {
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
TransactionType: 'PaymentChannelFund',
|
||||
Channel: computePaymentChannelHash(
|
||||
this.wallet.getClassicAddress(),
|
||||
wallet2.getClassicAddress(),
|
||||
paymentChannelResponse.result.tx_json.Sequence ?? 0,
|
||||
),
|
||||
Amount: '100',
|
||||
}
|
||||
|
||||
await testTransaction(this.client, paymentChannelFund, this.wallet)
|
||||
})
|
||||
})
|
||||
33
test/integration/transactions/trustSet.ts
Normal file
33
test/integration/transactions/trustSet.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
import { TrustSet } from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('TrustSet', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const tx: TrustSet = {
|
||||
TransactionType: 'TrustSet',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
LimitAmount: {
|
||||
currency: 'USD',
|
||||
issuer: wallet2.getClassicAddress(),
|
||||
value: '100',
|
||||
},
|
||||
}
|
||||
|
||||
await testTransaction(this.client, tx, this.wallet)
|
||||
})
|
||||
})
|
||||
@@ -2,7 +2,7 @@ import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { decode } from 'ripple-binary-codec'
|
||||
|
||||
import { Client, Wallet } from 'xrpl-local'
|
||||
import { Client, Wallet, Response } from 'xrpl-local'
|
||||
import { Payment, Transaction } from 'xrpl-local/models/transactions'
|
||||
import { computeSignedTransactionHash } from 'xrpl-local/utils/hashes'
|
||||
|
||||
@@ -73,18 +73,30 @@ export async function verifySubmittedTransaction(
|
||||
}
|
||||
}
|
||||
|
||||
export function verifySuccessfulResponse(response: Response): void {
|
||||
assert.equal(response.status, 'success')
|
||||
assert.equal(response.type, 'response')
|
||||
}
|
||||
|
||||
export async function testTransaction(
|
||||
client: Client,
|
||||
transaction: Transaction,
|
||||
wallet: Wallet,
|
||||
): Promise<void> {
|
||||
// Accept any un-validated changes.
|
||||
await ledgerAccept(client)
|
||||
|
||||
// sign/submit the transaction
|
||||
const response = await client.submitTransaction(wallet, transaction)
|
||||
|
||||
// check that the transaction was successful
|
||||
assert.equal(response.status, 'success')
|
||||
assert.equal(response.type, 'response')
|
||||
assert.equal(response.result.engine_result, 'tesSUCCESS')
|
||||
assert.equal(
|
||||
response.result.engine_result,
|
||||
'tesSUCCESS',
|
||||
response.result.engine_result_message,
|
||||
)
|
||||
|
||||
// check that the transaction is on the ledger
|
||||
const signedTx = _.omit(response.result.tx_json, 'hash')
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
mocha.ui('bdd')
|
||||
</script>
|
||||
|
||||
<script src="../testCompiledForWeb/index.js"></script>
|
||||
<script src="./testCompiledForWeb/index.js"></script>
|
||||
|
||||
<script>
|
||||
mocha.run()
|
||||
|
||||
@@ -180,6 +180,16 @@ export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
)
|
||||
} else if (request.data.closeServer) {
|
||||
conn.close()
|
||||
} else if (request.data.delayedResponseIn) {
|
||||
setTimeout(() => {
|
||||
conn.send(
|
||||
createResponse(request, {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {},
|
||||
}),
|
||||
)
|
||||
}, request.data.delayedResponseIn)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ export function assertResultMatch(
|
||||
* @param message - Expected error message/substring of the error message.
|
||||
*/
|
||||
export async function assertRejects(
|
||||
promise: PromiseLike<Record<string, unknown>>,
|
||||
promise: PromiseLike<any>,
|
||||
instanceOf: any,
|
||||
message?: string | RegExp,
|
||||
): Promise<void> {
|
||||
@@ -72,7 +72,7 @@ export async function assertRejects(
|
||||
|
||||
assert(error instanceof instanceOf, error.message)
|
||||
if (typeof message === 'string') {
|
||||
assert.strictEqual(error.message, message)
|
||||
assert.strictEqual(error.message, message, 'Messages do not match')
|
||||
} else if (message instanceof RegExp) {
|
||||
assert(message.test(error.message))
|
||||
}
|
||||
|
||||
25
test/utils/isValidAddress.ts
Normal file
25
test/utils/isValidAddress.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { isValidAddress } from 'xrpl-local'
|
||||
|
||||
describe('isValidAddress', function () {
|
||||
it('Validates valid classic address', function () {
|
||||
const classic = 'r3rhWeE31Jt5sWmi4QiGLMZnY3ENgqw96W'
|
||||
assert(isValidAddress(classic))
|
||||
})
|
||||
|
||||
it('Does not validate invalid classic address', function () {
|
||||
const classic = 'r3rhWeE31Jt5sWmi4QiGLMZnY3ENhqw96W'
|
||||
assert(!isValidAddress(classic))
|
||||
})
|
||||
|
||||
it('Validates valid X-Address', function () {
|
||||
const xAddress = 'XV5sbjUmgPpvXv4ixFWZ5ptAYZ6PD28Sq49uo34VyjnmK5H'
|
||||
assert(isValidAddress(xAddress))
|
||||
})
|
||||
|
||||
it('Does not validate invalid X-Address', function () {
|
||||
const xAddress = 'XV5sbjUmgPpvXv4ixFWZ5pfAYZ6PD28Sq49uo34VyjnmK5H'
|
||||
assert(!isValidAddress(xAddress))
|
||||
})
|
||||
})
|
||||
@@ -32,6 +32,6 @@ describe('Get Faucet URL', function () {
|
||||
|
||||
it('returns undefined if not a Testnet or Devnet server URL', function () {
|
||||
// Info: setupClient.setup creates a connection to 'localhost'
|
||||
assert.strictEqual(getFaucetUrl(this.client), undefined)
|
||||
assert.throws(() => getFaucetUrl(this.client))
|
||||
})
|
||||
})
|
||||
|
||||
79
test/webpack.config.js
Normal file
79
test/webpack.config.js
Normal file
@@ -0,0 +1,79 @@
|
||||
'use strict'
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const assert = require('assert')
|
||||
|
||||
function webpackForTest(testFileName) {
|
||||
const match = testFileName.match(/\/?([^\/]*)\.ts$/)
|
||||
if (!match) {
|
||||
assert(false, 'wrong filename:' + testFileName)
|
||||
}
|
||||
|
||||
const test = {
|
||||
mode: 'production',
|
||||
cache: true,
|
||||
externals: [
|
||||
{
|
||||
'xrpl-local': 'xrpl',
|
||||
net: 'null',
|
||||
},
|
||||
],
|
||||
entry: testFileName,
|
||||
output: {
|
||||
library: match[1].replace(/-/g, '_'),
|
||||
path: path.join(__dirname, './testCompiledForWeb/'),
|
||||
filename: match[1] + '.js',
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({ process: 'process/browser' }),
|
||||
new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /jayson/,
|
||||
use: 'null',
|
||||
},
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
compilerOptions: {
|
||||
composite: false,
|
||||
declaration: false,
|
||||
declarationMap: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
node: {
|
||||
global: true,
|
||||
__filename: false,
|
||||
__dirname: true,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
ws: './dist/npm/client/wsWrapper.js',
|
||||
'https-proxy-agent': false,
|
||||
},
|
||||
extensions: ['.ts', '.js', '.json'],
|
||||
fallback: {
|
||||
buffer: require.resolve('buffer/'),
|
||||
assert: require.resolve('assert/'),
|
||||
url: require.resolve('url/'),
|
||||
stream: require.resolve('stream-browserify'),
|
||||
crypto: require.resolve('crypto-browserify'),
|
||||
path: require.resolve('path-browserify'),
|
||||
http: require.resolve('stream-http'),
|
||||
},
|
||||
},
|
||||
}
|
||||
return test
|
||||
}
|
||||
|
||||
module.exports = [(env, argv) => webpackForTest('./test/integration/index.ts')]
|
||||
@@ -1,8 +1,6 @@
|
||||
'use strict'
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const webpack = require('webpack')
|
||||
const assert = require('assert')
|
||||
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
|
||||
|
||||
function getDefaultConfiguration() {
|
||||
@@ -51,78 +49,6 @@ function getDefaultConfiguration() {
|
||||
}
|
||||
}
|
||||
|
||||
function webpackForTest(testFileName) {
|
||||
const match = testFileName.match(/\/?([^\/]*)\.ts$/)
|
||||
if (!match) {
|
||||
assert(false, 'wrong filename:' + testFileName)
|
||||
}
|
||||
|
||||
const test = {
|
||||
cache: true,
|
||||
externals: [
|
||||
{
|
||||
'xrpl-local': 'xrpl',
|
||||
net: 'null',
|
||||
},
|
||||
],
|
||||
entry: testFileName,
|
||||
output: {
|
||||
library: match[1].replace(/-/g, '_'),
|
||||
path: path.join(__dirname, './testCompiledForWeb/'),
|
||||
filename: match[1] + '.js',
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({ process: 'process/browser' }),
|
||||
new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /jayson/,
|
||||
use: 'null',
|
||||
},
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
compilerOptions: {
|
||||
composite: false,
|
||||
declaration: false,
|
||||
declarationMap: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
node: {
|
||||
global: true,
|
||||
__filename: false,
|
||||
__dirname: true,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
ws: './dist/npm/client/wsWrapper.js',
|
||||
'https-proxy-agent': false,
|
||||
},
|
||||
extensions: ['.ts', '.js', '.json'],
|
||||
fallback: {
|
||||
buffer: require.resolve('buffer/'),
|
||||
assert: require.resolve('assert/'),
|
||||
url: require.resolve('url/'),
|
||||
stream: require.resolve('stream-browserify'),
|
||||
crypto: require.resolve('crypto-browserify'),
|
||||
path: require.resolve('path-browserify'),
|
||||
http: require.resolve('stream-http'),
|
||||
},
|
||||
},
|
||||
}
|
||||
return test
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
(env, argv) => {
|
||||
const config = getDefaultConfiguration()
|
||||
@@ -139,5 +65,4 @@ module.exports = [
|
||||
}
|
||||
return config
|
||||
},
|
||||
(env, argv) => webpackForTest('./test/integration/index.ts'),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user