Compare commits

..

57 Commits

Author SHA1 Message Date
Omar Khan
275c95752b release: v4.0.0 (#2739)
* update HISTORY

* update package.json
2024-07-16 14:20:55 -04:00
Chenna Keshava B S
3bc3c2029b feat: Upgrade to Node 18 and remove cross-fetch (#2678) (#2737)
* feat: Upgrade to Node 18 and remove cross-fetch (#2678)

BREAKING CHANGE: fetch now relies on the native javascript environment in browsers and node.js

Co-authored-by: justinr1234 <justinr1234@gmail.com>
2024-07-16 11:04:47 -07:00
tequ
c9ef96e0a2 Add transaction hash to ledger command response (#2717)
* add transaction hash to ledger command response

* Update packages/xrpl/src/models/ledger/Ledger.ts

* Update HISTORY.md

* delete unnesessary space
2024-07-12 09:57:24 -04:00
Mayukha Vadari
00f1a6bcdd feat: add feature RPC (#2719)
* add feature RPC

* export, add tests

* update history

* fix test

* update models

* update feature models to correctly handle both cases

* fix models/tests

* fix test, improve type

* undo type change

* fix test
2024-07-10 13:18:16 -04:00
dependabot[bot]
3858a09e1f build(deps-dev): bump ts-jest from 29.1.5 to 29.2.0 (#2729) 2024-07-09 15:25:33 +00:00
dependabot[bot]
3aaf526107 build(deps): bump ws from 8.17.1 to 8.18.0 (#2730) 2024-07-09 15:15:50 +00:00
Mayukha Vadari
1460cf5026 feat: add support for the fixPreviousTxnID amendment (#2720)
* add support for fixPreviousTxnID

* update history
2024-07-08 17:24:38 -04:00
dependabot[bot]
7e733c4446 build(deps-dev): bump @types/lodash from 4.17.4 to 4.17.6 (#2718)
Bumps [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) from 4.17.4 to 4.17.6.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash)

---
updated-dependencies:
- dependency-name: "@types/lodash"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-08 08:45:32 -05:00
dependabot[bot]
735ac2eb07 build(deps): bump @noble/curves from 1.4.0 to 1.4.2 (#2723) 2024-07-03 17:27:31 +00:00
dependabot[bot]
c79a5db8f2 build(deps-dev): bump typedoc from 0.26.2 to 0.26.3 (#2722)
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.26.2 to 0.26.3.
- [Release notes](https://github.com/TypeStrong/TypeDoc/releases)
- [Changelog](https://github.com/TypeStrong/typedoc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/TypeDoc/compare/v0.26.2...v0.26.3)

---
updated-dependencies:
- dependency-name: typedoc
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 11:02:18 -05:00
Omar Khan
8e2aba3b78 feat: add rippled API v2 support and use as default (#2656)
* add apiVersion support to requests and AccountInfoResponse v1/v2 types

* fix submitAndWait signature

* update docker container README

* update tests

* fix apiVersion param in wrong position of Client.request

* add integ tests

* update HISTORY.md

* fix request.api_version

* update RIPPLED_DOCKER_IMAGE to use v2.1.0

* refactor Client.request signature

* update rippled docker image

* fix Client.requestAll

* update rippled docker image to use v2.1.1

* update README

* use import type

* fix faucet; unrelated to PR

* add api_version v2 support and set as default while providing support for v1

* refactor: add apiVersion to Client

* resolve errors

* use DeliverMax for isPartialPayment check

* update fixtures

* resolve lint errors

* add API v1 support for isPartialPayment

* update CONTRIBUTING

* update accountTx JSDoc

* revert deleted JSDoc comments in accountTx

* update JSDoc for account_info response

* only use client.apiVersion in Client.request()

* add ledger_hash

* remove API v1 comment from v2 model

* update meta_blob JSDoc

* delete second AccountTxRequest matching

* add close_time_iso

* set close_time_iso as optional field

* add meta_blob to BaseResponse

* Revert "add meta_blob to BaseResponse"

This reverts commit 89794c629dc515915e28752d7c2552bfeab266a3.

* use DEFAULT_API_VERSION throughout call stack

* improve JSDoc explanation of ledger_index

* remove this.apiVersion from getLedgerIndex

* refactor Client.request()

* refactor RequestManger.resolve()

* add TODO to fix TxResponse type assertion

* use @category ResponsesV1 for API v1 types

* refactor accountTxHasPartialPayment()

* remove TODO
2024-06-28 08:26:21 -04:00
Chenna Keshava B S
39fed49654 Aliter: Implement DeliverMax alias in Payment transactions, through autofill method (#2689)
Co-authored-by: Omar Khan <khancodegt@gmail.com>
2024-06-27 09:46:49 -07:00
dependabot[bot]
a0678857a1 build(deps-dev): bump webpack from 5.91.0 to 5.92.1 (#2713) 2024-06-25 14:18:08 +00:00
dependabot[bot]
38e2091fd2 build(deps-dev): bump ts-jest from 29.1.4 to 29.1.5 (#2709) 2024-06-25 14:11:44 +00:00
dependabot[bot]
a528d6632a build(deps-dev): bump typedoc from 0.25.0 to 0.26.2 (#2712) 2024-06-25 13:59:07 +00:00
dependabot[bot]
ab081e7db9 build(deps): bump @scure/base from 1.1.6 to 1.1.7 (#2708)
Bumps [@scure/base](https://github.com/paulmillr/scure-base) from 1.1.6 to 1.1.7.
- [Release notes](https://github.com/paulmillr/scure-base/releases)
- [Commits](https://github.com/paulmillr/scure-base/compare/1.1.6...1.1.7)

---
updated-dependencies:
- dependency-name: "@scure/base"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com>
2024-06-24 19:03:54 -04:00
dependabot[bot]
493c56c0fa build(deps): bump ws from 8.17.0 to 8.17.1 (#2707)
Bumps [ws](https://github.com/websockets/ws) from 8.17.0 to 8.17.1.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.17.0...8.17.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com>
Co-authored-by: justinr1234 <justinr1234@gmail.com>
2024-06-24 15:07:04 -07:00
dependabot[bot]
c73b2c5a86 build(deps-dev): bump braces from 3.0.2 to 3.0.3 (#2706)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com>
2024-06-24 17:59:39 -04:00
Chenna Keshava B S
02e2b0e48e remove references to the hooks testnet faucet in xrpl.js codebase (#2711) 2024-06-20 17:18:11 -07:00
Zhiyuan Wang
d3b03a536d Add nfts_by_issuer data type (#2694)
* add nfts_by_issuer data type

* update HISTORY.md

* update HISTORY.md

* added to index and change field name

* change to added in history

* reformat change in history

* reformat history on bfts_by_issuer

---------

Authored-by: Kassaking <kassaking7@gmail.com>
2024-06-11 14:43:47 -04:00
dependabot[bot]
036f1f9850 build(deps-dev): bump @types/lodash from 4.17.1 to 4.17.4 (#2697) 2024-06-05 16:30:17 +00:00
Omar Khan
92849e57ce release 3.1.0 (#2703)
* update HISTORYs

* update HISTORY for isomorphic

* update package.json
2024-06-03 16:33:06 -04:00
dependabot[bot]
32f0d7b121 build(deps-dev): bump ts-jest from 29.1.2 to 29.1.4 (#2702) 2024-06-03 19:19:48 +00:00
Omar Khan
b27bbb49b3 feat: add input check for OracleSet params AssetPrice and Scale (#2699)
* add input check for AssetPrice and Scale being either both present or excluded
2024-05-23 17:32:36 -04:00
Omar Khan
23adb4924b feat: add Price Oracles support (#2688) 2024-05-23 12:10:00 -04:00
Mayukha Vadari
9b3bb9c14b fix: throw error if hexToBytes or hexToString is provided a string that is not in hex (#2657)
* better error handling

* fix browser tests

* add shared variable

* re-add test case
2024-05-08 13:02:34 -04:00
dependabot[bot]
d441361999 build(deps-dev): bump @types/lodash from 4.17.0 to 4.17.1 (#2691) 2024-05-08 16:46:07 +00:00
dependabot[bot]
fb94f2a020 build(deps): bump ws from 8.16.0 to 8.17.0 (#2685) 2024-05-08 16:39:03 +00:00
dependabot[bot]
7b56a49dae build(deps-dev): bump react from 18.2.0 to 18.3.1 (#2686) 2024-05-08 16:31:33 +00:00
Mayukha Vadari
212686baae fix: better error handling for the binary codec (#2693)
* better error handling

* respond to comments

* remove --watch
2024-05-08 12:20:43 -04:00
dependabot[bot]
4d6fef597c build(deps-dev): bump webpack-bundle-analyzer from 4.10.1 to 4.10.2 (#2681)
* build(deps-dev): bump webpack-bundle-analyzer from 4.10.1 to 4.10.2

Bumps [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) from 4.10.1 to 4.10.2.
- [Release notes](https://github.com/webpack-contrib/webpack-bundle-analyzer/releases)
- [Changelog](https://github.com/webpack-contrib/webpack-bundle-analyzer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/webpack-bundle-analyzer/compare/v4.10.1...v4.10.2)

---
updated-dependencies:
- dependency-name: webpack-bundle-analyzer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: fund wallet test

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Justin Reynolds <justinr1234@gmail.com>
2024-05-08 11:00:47 -05:00
Chenna Keshava B S
8b596a6687 update Migration guide: info about the changed behavior (#2659)
* generateSeed() update: If no algorithm is specified, use ed25519 algorithm by default.

This causes breakge in downstream dependencies such as Account class. Account.familySeed makes use of generateSeed

* update Migration guide: info about the changed behavior

* updates to MIGRATION guide -- suggestions from jackson mills

---------

Co-authored-by: Mayukha Vadari <mvadari@gmail.com>
2024-04-09 09:59:35 -07:00
dependabot[bot]
8afc9ad506 build(deps-dev): bump eslint from 8.56.0 to 8.57.0 (#2655)
Bumps [eslint](https://github.com/eslint/eslint) from 8.56.0 to 8.57.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.56.0...v8.57.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kausty Saxena <ksaxena@ripple.com>
2024-04-08 14:26:21 -05:00
dependabot[bot]
3b08d7d379 build(deps-dev): bump karma from 6.4.2 to 6.4.3 (#2654)
Bumps [karma](https://github.com/karma-runner/karma) from 6.4.2 to 6.4.3.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](https://github.com/karma-runner/karma/compare/v6.4.2...v6.4.3)

---
updated-dependencies:
- dependency-name: karma
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: justinr1234 <justinr1234@gmail.com>
2024-04-08 12:12:50 -05:00
Mayukha Vadari
616ad4af60 fix: add PreviousFields to DeletedNode metadata type (#2668) 2024-04-08 11:05:37 +02:00
Chenna Keshava B S
dbdb35abb5 rectify the flag name tfNoRippleDirect (#2647)
* rectify the flag name tfNoRippleDirect

* Update th History.md file

* use "Breaking Changes" heading in the API Changelog

* Update HISTORY.md

---------
2024-04-02 14:54:02 -04:00
Omar Khan
445a05e6ef fix: add missing lsfAMMNode flag (#2674)
* add missing lsfAMMNode flag

* update HISTORY

* update HISTORY
2024-03-28 19:03:30 -04:00
dependabot[bot]
ccad092fc2 build(deps-dev): bump webpack from 5.90.3 to 5.91.0 (#2673)
Bumps [webpack](https://github.com/webpack/webpack) from 5.90.3 to 5.91.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.90.3...v5.91.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com>
2024-03-25 14:21:51 -07:00
dependabot[bot]
faa23b430e build(deps): bump @scure/bip39 from 1.2.2 to 1.3.0 (#2672)
Bumps [@scure/bip39](https://github.com/paulmillr/scure-bip39) from 1.2.2 to 1.3.0.
- [Release notes](https://github.com/paulmillr/scure-bip39/releases)
- [Commits](https://github.com/paulmillr/scure-bip39/compare/1.2.2...1.3.0)

---
updated-dependencies:
- dependency-name: "@scure/bip39"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-25 14:10:55 -07:00
dependabot[bot]
923e5d16ac build(deps): bump @scure/bip32 from 1.3.3 to 1.4.0 (#2670)
Bumps [@scure/bip32](https://github.com/paulmillr/scure-bip32) from 1.3.3 to 1.4.0.
- [Release notes](https://github.com/paulmillr/scure-bip32/releases)
- [Commits](https://github.com/paulmillr/scure-bip32/compare/1.3.3...1.4.0)

---
updated-dependencies:
- dependency-name: "@scure/bip32"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-25 13:50:33 -07:00
dependabot[bot]
602ac481d7 build(deps-dev): bump follow-redirects from 1.15.4 to 1.15.6 (#2662)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.4 to 1.15.6.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Omar Khan <khancodegt@gmail.com>
2024-03-21 16:22:51 -04:00
Chenna Keshava B S
b322396a99 additional amm flags are introduced (#2667)
* additional amm flags are introduced

Co-authored-by: Mayukha Vadari <mvadari@gmail.com>

---------

Co-authored-by: Mayukha Vadari <mvadari@gmail.com>
2024-03-21 10:27:30 -07:00
dependabot[bot]
b9af7bdb6c build(deps): bump @noble/curves from 1.3.0 to 1.4.0 (#2664) 2024-03-19 00:43:05 +00:00
dependabot[bot]
bdb3ad7f3e build(deps-dev): bump @types/lodash from 4.14.202 to 4.17.0 (#2663)
Bumps [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) from 4.14.202 to 4.17.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash)

---
updated-dependencies:
- dependency-name: "@types/lodash"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-18 15:50:06 -07:00
dependabot[bot]
1fdbf85d47 build(deps): bump @noble/hashes from 1.3.3 to 1.4.0 (#2665)
Bumps [@noble/hashes](https://github.com/paulmillr/noble-hashes) from 1.3.3 to 1.4.0.
- [Release notes](https://github.com/paulmillr/noble-hashes/releases)
- [Commits](https://github.com/paulmillr/noble-hashes/compare/1.3.3...1.4.0)

---
updated-dependencies:
- dependency-name: "@noble/hashes"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-18 15:38:57 -07:00
zgrguric
3e3911464f Update APPLICATIONS.md - Add XRPLWin to the list (#2619)
Update APPLICATIONS.md

Co-authored-by: Jackson Mills <jmills@ripple.com>
Co-authored-by: Caleb Kniffen <ckniffen@ripple.com>
Co-authored-by: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com>
2024-03-14 17:14:01 -04:00
Jackson Mills
be732a4a6b Update docs for Channel, ClientOptions, and ConnectionUserOptions (#2630)
* Update docs for three objects

* Fix my updated Channel type

* Fix docs wording in client

* Export channel again

* Update HISTORY.md

* Lint
2024-02-26 17:37:58 -05:00
dependabot[bot]
e505843dc6 build(deps-dev): bump ip from 2.0.0 to 2.0.1 (#2652) 2024-02-21 17:08:35 +00:00
dependabot[bot]
ff9489ba10 build(deps-dev): bump webpack from 5.90.1 to 5.90.3 (#2651) 2024-02-20 17:29:34 +00:00
Mayukha Vadari
365763d6f7 fix: get client.requestAll to handle filters better (#2649)
* fix requestAll issue

* update changelog

* fix typo
2024-02-15 19:20:22 -05:00
dependabot[bot]
9349a6ba1a build(deps-dev): bump webpack from 5.90.0 to 5.90.1 (#2646)
Bumps [webpack](https://github.com/webpack/webpack) from 5.90.0 to 5.90.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.90.0...v5.90.1)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-12 13:21:28 -05:00
dependabot[bot]
34f35a5912 build(deps): bump ws from 8.14.2 to 8.16.0 (#2638)
Bumps [ws](https://github.com/websockets/ws) from 8.14.2 to 8.16.0.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.14.2...8.16.0)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-12 13:14:56 -05:00
dependabot[bot]
05f16068ff build(deps-dev): bump karma-webpack from 5.0.0 to 5.0.1 (#2644)
Bumps [karma-webpack](https://github.com/webpack-contrib/karma-webpack) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/webpack-contrib/karma-webpack/releases)
- [Changelog](https://github.com/codymikol/karma-webpack/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/karma-webpack/compare/v5.0.0...v5.0.1)

---
updated-dependencies:
- dependency-name: karma-webpack
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Omar Khan <khancodegt@gmail.com>
2024-02-12 12:42:08 -05:00
Jackson Mills
ddda7f4552 Fix: Migration guide package version formatting (#2635)
Update MIGRATION.md with better formatting on package versions

Co-authored-by: Omar Khan <khancodegt@gmail.com>
2024-02-12 12:29:00 -05:00
dependabot[bot]
38406212c3 build(deps-dev): bump @types/jest from 29.5.11 to 29.5.12 (#2641)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 29.5.11 to 29.5.12.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-12 12:17:39 -05:00
dependabot[bot]
62a0d39ac3 build(deps): bump @scure/bip39 from 1.2.1 to 1.2.2 (#2640)
Bumps [@scure/bip39](https://github.com/paulmillr/scure-bip39) from 1.2.1 to 1.2.2.
- [Release notes](https://github.com/paulmillr/scure-bip39/releases)
- [Commits](https://github.com/paulmillr/scure-bip39/compare/1.2.1...1.2.2)

---
updated-dependencies:
- dependency-name: "@scure/bip39"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-12 12:07:13 -05:00
dependabot[bot]
0e6ab4e4ee build(deps): bump @scure/bip32 from 1.3.2 to 1.3.3 (#2639)
Bumps [@scure/bip32](https://github.com/paulmillr/scure-bip32) from 1.3.2 to 1.3.3.
- [Release notes](https://github.com/paulmillr/scure-bip32/releases)
- [Commits](https://github.com/paulmillr/scure-bip32/compare/1.3.2...1.3.3)

---
updated-dependencies:
- dependency-name: "@scure/bip32"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-12 11:56:04 -05:00
116 changed files with 4519 additions and 15431 deletions

View File

@@ -170,3 +170,11 @@ fixNFTokenRemint
# 2.0.0 Amendments
XChainBridge
DID
# 2.2.0-b3 Amendments
fixNFTokenReserve
fixInnerObjTemplate
fixAMMOverflowOffer
PriceOracle
fixEmptyDID
fixXChainRewardRounding
fixPreviousTxnID

View File

@@ -4,7 +4,7 @@
name: Node.js CI
env:
RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.0.0-b4
RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.2.0-b3
on:
push:
@@ -19,7 +19,7 @@ jobs:
strategy:
matrix:
node-version: [16.x]
node-version: [18.x]
steps:
- uses: actions/checkout@v3
@@ -60,7 +60,7 @@ jobs:
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v3
@@ -101,7 +101,7 @@ jobs:
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v3
@@ -153,7 +153,7 @@ jobs:
strategy:
matrix:
node-version: [16.x]
node-version: [18.x]
steps:
- uses: actions/checkout@v3
@@ -205,7 +205,7 @@ jobs:
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v3

View File

@@ -39,7 +39,7 @@
"enable": true
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,

View File

@@ -58,6 +58,10 @@ Warning: Use at your own risk.
XRP Ledger explorer, API, metrics, and analytics using a graph database that is synchronized live with the XRPL.
- **[XRPLWin](https://xrplwin.com)**
XRP Ledger and Xahau explorer, Hooks explorer, metrics, and analytics using a XWA backend that is synchronized live with the XRPL and Xahau.
## Data monitoring
- **[zerptracker](https://zerptracker.com)**

View File

@@ -12,7 +12,7 @@
### Requirements
We use Node v16 for development - that is the version that our linters require.
We use Node v18 for development - that is the version that our linters require.
You must also use `npm` v7. You can check your `npm` version with:
```bash
@@ -90,7 +90,7 @@ This should be run from the `xrpl.js` top level folder (one above the `packages`
```bash
npm run build
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
docker run -p 6006:6006 --interactive -t --volume $PWD/.ci-config:/opt/ripple/etc/ --platform linux/amd64 rippleci/rippled:2.0.0-b3 /opt/ripple/bin/rippled -a --conf /opt/ripple/etc/rippled.cfg
docker run -p 6006:6006 --interactive -t --volume $PWD/.ci-config:/opt/ripple/etc/ --platform linux/amd64 rippleci/rippled:2.2.0-b3 /opt/ripple/bin/rippled -a --conf /opt/ripple/etc/rippled.cfg
npm run test:browser
```
@@ -104,6 +104,8 @@ The 4 packages currently here are:
2. ripple-binary-codec - A library for serializing and deserializing transactions for the ledger.
3. ripple-keypairs - A library for generating and using cryptographic keypairs.
4. ripple-address-codec - A library for encoding and decoding XRP Ledger addresses and seeds.
5. isomorphic - A collection of isomorphic implementations of crypto and utility functions.
6. secret-numbers - Generate XRPL Accounts with a number-based secret: 8 chunks of 6 digits.
Each package has it's own README which dives deeper into what it's main purpose is, and the core functionality it offers.
They also run tests independently as they were originally in separate repositories.

View File

@@ -2,12 +2,15 @@
In xrpl.js 3.0, we've made significant improvements that result in a 60% reduction in bundle size for browser applications. We've also eliminated the need for polyfills with minimal disruption to existing code. This was achieved by replacing node-specific dependencies with ones that are compatible with browsers.
The main change you'll notice is the update replacing `Buffer` with `Uint8Array` across the board. This was done since browsers don't support `Buffer`. Fortunately, this transition is relatively straightforward, as `Buffer` is a subclass of `Uint8Array`, meaning in many circumstances `Buffer` can be directly replaced by `Uint8Array`. The primary difference is that `Buffer` has additional helper functions. We've listed the affected client library functions below in the `Uint8Array` section for your reference.
The two main changes you'll notice are:
* A breaking change to `Wallet` object creation, to use a more performant algorithm by default. See [here](#8-wallet-functions-default-to-ed25519-instead-of-secp256k1-signing-algorithm) for details.
* Replacing `Buffer` with `Uint8Array` across the board. This was done since browsers don't support `Buffer`. Fortunately, this transition is relatively straightforward, as `Buffer` is a subclass of `Uint8Array`, meaning in many circumstances `Buffer` can be directly replaced by `Uint8Array`. The primary difference is that `Buffer` has additional helper functions. We've listed the affected client library functions below in the `Uint8Array` section for your reference.
This migration guide also applies to:
`ripple-address-codec` 4.3.1 -> 5.0.0
`ripple-binary-codec` 1.11.0 -> 2.0.0
`ripple-keypairs` 1.3.1 -> 2.0.0
- `ripple-address-codec` 4.3.1 -> 5.0.0
- `ripple-binary-codec` 1.11.0 -> 2.0.0
- `ripple-keypairs` 1.3.1 -> 2.0.0
- `xrpl-secret-numbers` 0.3.4 -> `@xrplf/secret-numbers` 1.0.0
# Why update to 3.0?
@@ -229,9 +232,27 @@ This was done to remove a hard dependency on `https-proxy-agent` when running
authorization: 'authorization'
}`
### 8. Bug fix: Setting an explicit `algorithm` when generating a wallet works now
### 8. `Wallet` functions default to `ed25519` instead of `secp256k1` signing algorithm
`Wallet.generate()` and `Wallet.fromSeed` were ignoring the `algorithm` parameter. This means that if you were manually specifying `algorithm` in any `Wallet` constructors, you may generate a different `Wallet` keypair when upgrading to 3.0. In that case to get the same generated wallets as before, dont specify the `algorithm` parameter.
In previous releases of this library, `Wallet.generate()` and `Wallet.fromSeed` were ignoring the `algorithm` parameter. Instead, the algorithm was assumed from the seed provided; if it started with `sEd`, it would use `ed25519`, and otherwise it would use `secp256k1`. However, seeds do not actually have algorithms; a seed starting with `s...` can still use the `ed25519` algorithm.
With 3.0, we updated the default signing algorithm used by the `Wallet` object to always be `ed25519` in order to default to the higher-performance algorithm. This is a breaking change to all functions used to generate a Wallet, so if you have a pre-existing XRPL account that you're using to generate a specific Wallet using older versions of xrpl.js, you may need to specify that you are using `secp256k1` as the algorithm to decode your private key / seed / etc to get the same behavior as before. See below for specifically how to update your code.
If you are creating new accounts each time (ex. via `Client.fundWallet` or `Wallet.generate`), you do not need to specify the signing algorithm.
**Before**
```
Wallet.fromSeed('s...')
Wallet.fromEntropy(entropy)
deriveKeyPair(seed="s...")
```
**After**
```
Wallet.fromSeed(seed='s...',algorithm: 'ecdsa-secp256k1')
Wallet.fromEntropy(entropy, opts={algorithm: 'ecdsa-secp256k1'})
deriveKeypair(seed='s...', opts={ algorithm: 'ecdsa-secp256k1' }) (ripple-keypairs)
```
### 9. `AssertionError` → `Error`

View File

@@ -19,13 +19,13 @@ See the full reference documentation for all classes, methods, and utilities.
4. Subscribing to changes in the ledger ([Ex. ledger, transactions, & more...](https://xrpl.org/subscribe.html))
5. Parsing ledger data into more convenient formats ([`xrpToDrops`](https://js.xrpl.org/functions/xrpToDrops.html) and [`rippleTimeToISOTime`](https://js.xrpl.org/functions/rippleTimeToISOTime.html))
All of which works in Node.js (tested for v16+) & web browsers (tested for Chrome).
All of which works in Node.js (tested for v18+) & web browsers (tested for Chrome).
# Quickstart
### Requirements
+ **[Node.js v16](https://nodejs.org/)** is recommended. We also support v18 and v20. Other versions may work but are not frequently tested.
+ **[Node.js v18](https://nodejs.org/)** is recommended. We also support v20. Other versions may work but are not frequently tested.
### Installing xrpl.js
@@ -56,7 +56,7 @@ async function main() {
});
console.log(response);
client.disconnect();
await client.disconnect();
}
main();
```

16606
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@
"@types/chai": "^4.2.21",
"@types/jest": "^29.2.2",
"@types/lodash": "^4.14.136",
"@types/node": "^16.18.38",
"@types/node": "^18.19.29",
"@types/ws": "^8.2.0",
"@typescript-eslint/eslint-plugin": "^5.28.0",
"@typescript-eslint/parser": "^5.28.0",
@@ -64,7 +64,7 @@
"./packages/*"
],
"engines": {
"node": ">=16.0.0",
"node": ">=18.0.0",
"npm": ">=7.10.0 < 10.0.0"
}
}

View File

@@ -1,5 +1,13 @@
# @xrplf/isomorphic Release History
## Unreleased
## 1.0.1 (2024-06-03)
### Fixed
* Throw error if `hexToBytes` or `hexToString` is provided a string that is not in hex
## 1.0.0 (2024-02-01)
Initial release providing isomorphic and tree-shakable implementations of:
@@ -14,21 +22,3 @@ Initial release providing isomorphic and tree-shakable implementations of:
* randomBytes
* stringToHex
* ws
## 1.0.0 Beta 1 (2023-11-30)
## Added
* hexToString
* stringToHex
## 1.0.0 Beta 0 (2023-10-19)
Initial release providing isomorphic and tree-shakable implementations of:
* ripemd160
* sha256
* sha512
* bytesToHash
* hashToBytes
* randomBytes
* ws_

View File

@@ -1,6 +1,6 @@
{
"name": "@xrplf/isomorphic",
"version": "1.0.0",
"version": "1.0.1",
"description": "A collection of isomorphic and tree-shakeable crypto hashes and utils for xrpl.js",
"keywords": [
"crypto",
@@ -33,7 +33,7 @@
"ws": "^8.13.0"
},
"devDependencies": {
"@types/node": "^16.18.38",
"@types/node": "^18.18.38",
"@types/ws": "^8.5.6"
},
"repository": {
@@ -43,6 +43,6 @@
"license": "ISC",
"prettier": "@xrplf/prettier-config",
"engines": {
"node": ">=16.0.0"
"node": ">=18.0.0"
}
}

View File

@@ -9,6 +9,7 @@ import type {
RandomBytesFn,
StringToHexFn,
} from './types'
import { HEX_REGEX } from './shared'
/* eslint-disable func-style -- Typed to ensure uniformity between node and browser implementations and docs */
export const bytesToHex: typeof BytesToHexFn = (bytes) => {
@@ -22,6 +23,9 @@ export const bytesToHex: typeof BytesToHexFn = (bytes) => {
export const hexToBytes: typeof HexToBytesFn = (hex): Uint8Array => {
const len = hex.length
const array = new Uint8Array(len / 2)
if (!HEX_REGEX.test(hex)) {
throw new Error('Invalid hex string')
}
for (let i = 0; i < array.length; i++) {
const j = i * 2
const hexByte = hex.slice(j, j + 2)

View File

@@ -1,6 +1,7 @@
import { randomBytes as cryptoRandomBytes } from 'crypto'
import type { BytesToHexFn, HexToBytesFn, RandomBytesFn } from './types'
import { HexToStringFn, StringToHexFn } from './types'
import { HEX_REGEX } from './shared'
const OriginalBuffer = Symbol('OriginalBuffer')
@@ -64,6 +65,9 @@ export const bytesToHex: typeof BytesToHexFn = (bytes) => {
}
export const hexToBytes: typeof HexToBytesFn = (hex) => {
if (!HEX_REGEX.test(hex)) {
throw new Error('Invalid hex string')
}
return toUint8Array(Buffer.from(hex, 'hex'))
}
@@ -75,6 +79,9 @@ export const hexToString: typeof HexToStringFn = (
hex: string,
encoding = 'utf8',
): string => {
if (!HEX_REGEX.test(hex)) {
throw new Error('Invalid hex string')
}
return new TextDecoder(encoding).decode(hexToBytes(hex))
}

View File

@@ -1,5 +1,7 @@
import { concatBytes } from '@noble/hashes/utils'
export const HEX_REGEX = /^[A-F0-9]*$/iu
export function concat(views: Uint8Array[]): Uint8Array {
return concatBytes(...views)
}

View File

@@ -23,10 +23,18 @@ describe('utils', function () {
expect(hexToBytes('DEADBEEF')).toEqual(new Uint8Array([222, 173, 190, 239]))
})
it('hexToBytes - DEADBEEF', () => {
expect(hexToBytes('DEADBEEF')).toEqual(new Uint8Array([222, 173, 190, 239]))
})
it('bytesToHex - DEADBEEF', () => {
expect(bytesToHex([222, 173, 190, 239])).toEqual('DEADBEEF')
})
it('bytesToHex - bad hex', () => {
expect(() => hexToBytes('hello')).toThrow(new Error('Invalid hex string'))
})
it('bytesToHex - 010203', () => {
expect(bytesToHex([1, 2, 3])).toEqual('010203')
})
@@ -43,6 +51,10 @@ describe('utils', function () {
expect(hexToString('6465616462656566D68D')).toEqual('deadbeef֍')
})
it('hexToString - bad hex', () => {
expect(() => hexToString('hello')).toThrow(new Error('Invalid hex string'))
})
it('stringToHex - deadbeef+infinity symbol (utf8)', () => {
expect(stringToHex('deadbeef֍')).toEqual('6465616462656566D68D')
})

View File

@@ -15,25 +15,6 @@
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
* Execute test in a browser in addition to node
## 5.0.0 Beta 1 (2023-11-30)
### Breaking Changes
* `Buffer` has been replaced with `UInt8Array` for both params and return values. `Buffer` may continue to work with params since they extend `UInt8Arrays`.
### Changes
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 5.0.0 Beta 0 (2023-10-19)
### Breaking Changes
* Bump typescript to 5.x
* Remove Node 14 support
* Remove `assert` dependency. If you were catching `AssertionError` you need to change to `Error`.
* Remove `create-hash` in favor of `@noble/hashes`
### Changes
* Execute test in a browser in addition to node
## 4.3.1 (2023-09-27)
### Fixed
* Fix source-maps not finding their designated source

View File

@@ -34,6 +34,6 @@
},
"prettier": "@xrplf/prettier-config",
"engines": {
"node": ">= 16"
"node": ">= 18"
}
}

View File

@@ -2,6 +2,14 @@
## Unreleased
## 2.1.0 (2024-06-03)
### Added
* Support for the Price Oracles amendment (XLS-47).
### Fixed
* Better error handling/error messages for serialization/deserialization errors.
## 2.0.0 (2024-02-01)
### BREAKING CHANGES
@@ -19,23 +27,6 @@
* `Comparable` is now a generic type so that it allows `compareTo` methods to take more that the type itself.
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 2.0.0 Beta 1 (2023-11-30)
### Breaking Changes
* `Buffer` has been replaced with `UInt8Array` for both params and return values. `Buffer` may continue to work with params since they extend `UInt8Arrays`.
### Changes
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 2.0.0 Beta 0 (2023-10-19)
### Breaking Changes
* Bump typescript to 5.x
* Remove Node 14 support
* Remove decimal.js and big-integer. Use `BigNumber` from `bignumber.js` instead of `Decimal` and the native `BigInt` instead of `bigInt`.
* Remove `assert` dependency. If you were catching `AssertionError` you need to change to `Error`.
* Remove `create-hash` in favor of `@noble/hashes`
### Changes
* Update type definitions which causing errors in tests that the code already supported
* `makeParser` to accept a `Buffer` in addition to `string`

View File

@@ -1,6 +1,6 @@
{
"name": "ripple-binary-codec",
"version": "2.0.0",
"version": "2.1.0",
"description": "XRP Ledger binary codec",
"files": [
"dist/*",
@@ -11,7 +11,7 @@
"test": "test"
},
"dependencies": {
"@xrplf/isomorphic": "^1.0.0",
"@xrplf/isomorphic": "^1.0.1",
"bignumber.js": "^9.0.0",
"ripple-address-codec": "^5.0.0"
},
@@ -41,6 +41,6 @@
"readmeFilename": "README.md",
"prettier": "@xrplf/prettier-config",
"engines": {
"node": ">= 16"
"node": ">= 18"
}
}

View File

@@ -23,6 +23,7 @@
"UInt512": 23,
"Issue": 24,
"XChainBridge": 25,
"Currency": 26,
"Transaction": 10001,
"LedgerEntry": 10002,
"Validation": 10003,
@@ -51,6 +52,7 @@
"NFTokenOffer": 55,
"AMM": 121,
"DID": 73,
"Oracle": 128,
"Any": -3,
"Child": -2,
"Nickname": 110,
@@ -208,6 +210,16 @@
"type": "UInt8"
}
],
[
"Scale",
{
"nth": 4,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"type": "UInt8"
}
],
[
"TickSize",
{
@@ -498,6 +510,16 @@
"type": "UInt32"
}
],
[
"LastUpdateTime",
{
"nth": 15,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"type": "UInt32"
}
],
[
"HighQualityIn",
{
@@ -828,6 +850,16 @@
"type": "UInt32"
}
],
[
"OracleDocumentID",
{
"nth": 51,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"type": "UInt32"
}
],
[
"IndexNext",
{
@@ -1028,6 +1060,16 @@
"type": "UInt64"
}
],
[
"AssetPrice",
{
"nth": 23,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"type": "UInt64"
}
],
[
"EmailHash",
{
@@ -1918,6 +1960,26 @@
"type": "Blob"
}
],
[
"AssetClass",
{
"nth": 28,
"isVLEncoded": true,
"isSerialized": true,
"isSigningField": true,
"type": "Blob"
}
],
[
"Provider",
{
"nth": 29,
"isVLEncoded": true,
"isSerialized": true,
"isSigningField": true,
"type": "Blob"
}
],
[
"Account",
{
@@ -2128,6 +2190,26 @@
"type": "PathSet"
}
],
[
"BaseAsset",
{
"nth": 1,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"type": "Currency"
}
],
[
"QuoteAsset",
{
"nth": 2,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"type": "Currency"
}
],
[
"LockingChainIssue",
{
@@ -2458,6 +2540,16 @@
"type": "STObject"
}
],
[
"PriceData",
{
"nth": 32,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"type": "STObject"
}
],
[
"Signers",
{
@@ -2628,6 +2720,16 @@
"type": "STArray"
}
],
[
"PriceDataSeries",
{
"nth": 24,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"type": "STArray"
}
],
[
"AuthAccounts",
{
@@ -2656,6 +2758,7 @@
"telWRONG_NETWORK": -386,
"telREQUIRES_NETWORK_ID": -385,
"telNETWORK_ID_MAKES_TX_NON_CANONICAL": -384,
"telENV_RPC_FAILED": -383,
"temMALFORMED": -299,
"temBAD_AMOUNT": -298,
@@ -2703,6 +2806,8 @@
"temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT": -256,
"temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT": -255,
"temEMPTY_DID": -254,
"temARRAY_EMPTY": -253,
"temARRAY_TOO_LARGE": -252,
"tefFAILURE": -199,
"tefALREADY": -198,
@@ -2739,7 +2844,6 @@
"terQUEUED": -89,
"terPRE_TICKET": -88,
"terNO_AMM": -87,
"terSUBMITTED": -86,
"tesSUCCESS": 0,
@@ -2815,7 +2919,11 @@
"tecXCHAIN_SELF_COMMIT": 184,
"tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR": 185,
"tecXCHAIN_CREATE_ACCOUNT_DISABLED": 186,
"tecEMPTY_DID": 187
"tecEMPTY_DID": 187,
"tecINVALID_UPDATE_TIME": 188,
"tecTOKEN_PAIR_NOT_FOUND": 189,
"tecARRAY_EMPTY": 190,
"tecARRAY_TOO_LARGE": 191
},
"TRANSACTION_TYPES": {
"Invalid": -1,
@@ -2864,6 +2972,8 @@
"XChainCreateBridge": 48,
"DIDSet": 49,
"DIDDelete": 50,
"OracleSet": 51,
"OracleDelete": 52,
"EnableAmendment": 100,
"SetFee": 101,
"UNLModify": 102

View File

@@ -144,14 +144,18 @@ class BinaryParser {
if (type === 0) {
type = this.readUInt8()
if (type === 0 || type < 16) {
throw new Error('Cannot read FieldOrdinal, type_code out of range')
throw new Error(
`Cannot read FieldOrdinal, type_code ${type} out of range`,
)
}
}
if (nth === 0) {
nth = this.readUInt8()
if (nth === 0 || nth < 16) {
throw new Error('Cannot read FieldOrdinal, field_code out of range')
throw new Error(
`Cannot read FieldOrdinal, field_code ${nth} out of range`,
)
}
}

View File

@@ -33,6 +33,9 @@ class Blob extends SerializedType {
}
if (typeof value === 'string') {
if (!/^[A-F0-9]*$/iu.test(value)) {
throw new Error('Cannot construct Blob from a non-hex string')
}
return new Blob(hexToBytes(value))
}

View File

@@ -14,7 +14,13 @@ const OBJECT_END_MARKER = Uint8Array.from([0xe1])
*/
function isObjects(args): args is Array<JsonObject> {
return (
Array.isArray(args) && (args.length === 0 || typeof args[0] === 'object')
Array.isArray(args) &&
args.every(
(arg) =>
typeof arg === 'object' &&
Object.keys(arg).length === 1 &&
typeof Object.values(arg)[0] === 'object',
)
)
}

View File

@@ -238,19 +238,19 @@ function fieldParsingTests() {
it('Field throws when type code out of range', () => {
const parser = makeParser('0101')
expect(() => parser.readField()).toThrow(
new Error('Cannot read FieldOrdinal, type_code out of range'),
new Error('Cannot read FieldOrdinal, type_code 1 out of range'),
)
})
it('Field throws when field code out of range', () => {
const parser = makeParser('1001')
expect(() => parser.readFieldOrdinal()).toThrow(
new Error('Cannot read FieldOrdinal, field_code out of range'),
new Error('Cannot read FieldOrdinal, field_code 1 out of range'),
)
})
it('Field throws when both type and field code out of range', () => {
const parser = makeParser('000101')
expect(() => parser.readFieldOrdinal()).toThrow(
new Error('Cannot read FieldOrdinal, type_code out of range'),
new Error('Cannot read FieldOrdinal, type_code 1 out of range'),
)
})
it('readUIntN', () => {

View File

@@ -4868,6 +4868,36 @@
"TxnSignature": "AACD31A04CAE14670FC483A1382F393AA96B49C84479B58067F049FBD772999325667A6AA2520A63756EE84F3657298815019DD56A1AECE796B08535C4009C08",
"URI": "6469645F6578616D706C65"
}
},
{
"binary": "1200332FFFFFFFFF2033000004D2750B6469645F6578616D706C65701C0863757272656E6379701D0870726F7669646572811401476926B590BA3245F63C829116A0A3AF7F382DF018E020301700000000000001E2041003011A0000000000000000000000000000000000000000021A0000000000000000000000005553440000000000E1F1",
"json": {
"TransactionType": "OracleSet",
"Account": "rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8",
"OracleDocumentID": 1234,
"LastUpdateTime": 4294967295,
"PriceDataSeries": [
{
"PriceData": {
"BaseAsset": "XRP",
"QuoteAsset": "USD",
"AssetPrice": "00000000000001E2",
"Scale": 3
}
}
],
"Provider": "70726F7669646572",
"URI": "6469645F6578616D706C65",
"AssetClass": "63757272656E6379"
}
},
{
"binary": "1200342033000004D2811401476926B590BA3245F63C829116A0A3AF7F382D",
"json": {
"TransactionType": "OracleDelete",
"Account": "rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8",
"OracleDocumentID": 1234
}
}
],
"ledgerData": [{

View File

@@ -19,29 +19,6 @@
* Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead.
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 2.0.0 Beta 1 (2023-11-30)
### Breaking Changes
* `Buffer` has been replaced with `UInt8Array` for both params and return values. `Buffer` may continue to work with params since they extend `UInt8Arrays`.
### Changes
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 2.0.0 Beta 0 (2023-10-19)
### Breaking Changes
* Bump typescript to 5.x
* Remove Node 14 support
* Remove `assert` dependency. If you were catching `AssertionError` you need to change to `Error`.
* Fix `deriveKeypair` ignoring manual decoding algorithm. (Specifying algorithm=`ed25519` in `opts` now works on secrets like `sNa1...`)
* Remove `crypto` polyfills, `create-hash`, `elliptic`, `hash.js`, and their many dependencies in favor of `@noble/hashes` and `@nobel/curves`
* Remove `bytesToHex` and `hexToBytes`. They can now be found in `@xrplf/isomorphic/utils`
* `verifyTransaction` will throw an error if there is no signature
* Improved key algorithm detection. It will now throw Errors with helpful messages
### Changes
* Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead.
## 1.3.1 (2023-09-27)
### Fixed
* Fix source-maps not finding their designated source

View File

@@ -36,6 +36,6 @@
"license": "ISC",
"prettier": "@xrplf/prettier-config",
"engines": {
"node": ">= 16"
"node": ">= 18"
}
}

View File

@@ -19,24 +19,3 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
* Unit tests run in a browser and node.
* Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead.
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 1.0.0 Beta 1 (2023-11-30)
### BREAKING CHANGES:
* Moved all methods that were on `Utils` are now individually exported.
* `Buffer` has been replaced with `UInt8Array` for both params and return values. `Buffer` may continue to work with params since they extend `UInt8Arrays`.
### Changes
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 1.0.0 Beta 0 (2023-10-19)
* Add `xrpl-secret-numbers` by @WietseWind to the mono repo.
* `unpkg` and `jsdelivr` support was simplified.
* Unit tests run in a browser and node.
* Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead.
### BREAKING CHANGES:
* `xrpl-secret-numbers` is now `@xrplf/secret-numbers`.
* The bundled file produced changed from `dist/browerified.js` to `build/xrplf-secret-numbers-latest.js`.
* Bundle variable is `xrplf_secret_numbers` instead of using browserify's loader.

View File

@@ -2,7 +2,36 @@
Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xrpl-announce) for release announcements. We recommend that xrpl.js (ripple-lib) users stay up-to-date with the latest stable release.
## Unreleased
## 4.0.0 (2024-07-15)
### BREAKING CHANGES
* Use rippled api_version v2 as default while maintaining support for v1.
### Added
* Add `nfts_by_issuer` clio-only API definition
* Support for the `fixPreviousTxnID` amendment.
* Support for the user version of the `feature` RPC.
* Add `hash` field to `ledger` command response
### Removed
* Remove references to the Hooks testnet faucet in the xrpl.js code repository.
## 3.1.0 (2024-06-03)
### BREAKING CHANGES
* Small fix in the API to use a new flag name `tfNoDirectRipple` instead of the existing flag name `tfNoRippleDirect`
* Node.js has been upgraded to a minimum version of 18
* `fetch` now relies on the native javascript environment in browsers and Node.js
### Added
* Support for the Price Oracles amendment (XLS-47).
### Fixed
* Typo in `Channel` type `source_tab` -> `source_tag`
* Fix `client.requestAll` to handle filters better
* Add the missing `AMMDeposit` flag `tfTwoAssetIfEmpty`
* Add missing `lsfAMMNode` flag to `RippleState` ledger object
* Add `PreviousFields` to `DeletedNode` metadata type
## 3.0.0 (2024-02-01)
@@ -52,80 +81,6 @@ Bundler configurations are much more simplified. See [../UNIQUE_STEPS](Unique St
* Deprecated:
* `convertHexToString` in favor of `@xrplf/isomorphic/utils`'s `hexToString`
* `convertStringToHex` in favor of `@xrplf/isomorphic/utils`'s `stringToHex`
## 3.0.0 Beta 1 (2023-11-30)
### Breaking Changes
* `Transaction` type has been redefined to include all transactions and `SubmittableTransaction` was created to define the old value. The following functions which only handle transactions to be submitted now use `SubmittableTransaction`:
* `Client.autofill`
* `Client.submit`
* `Client.submitAndWait`
* `Client.prepareTransaction`
* `getSignedTx`
* `isAccountDelete`
* `dropsToXRP` and `Client.getXrpBalance` now return a `number` instead of a `string`
* `Buffer` has been replaced with `UInt8Array` for both params and return values. `Buffer` may continue to work with params since they extend `UInt8Arrays`.
### Bundling Changes
* `Buffer` and `process` polyfills are no longer required.
### Changes
* Deprecated:
* `convertHexToString` in favor of `@xrplf/isomorphic/utils`'s `hexToString`
* `convertStringToHex` in favor of `@xrplf/isomorphic/utils`'s `stringToHex`
* Remove `lodash` as a dependency
* Remove many polyfills that were only used for testing in the browser
* Remove `util` from bundle by switching `inspect` to `JSON.stringify`
* Add type for metadata for specific transactions(`Payment`, `NFTokenMint`, `NFTokenCreateOffer`, `NFTokenAcceptOffer`, `NFTokenCancelOffer`)
### Fixed
* Fixed Wallet.generate() ignoring the `algorithm` parameter (Only a problem once binary-codec fix for `derive_keypair` is added)
* Fixed Wallet.fromSeed() ignoring the `algorithm` parameter
* Added pseudo-transaction support to hash functions and response types
## 3.0.0 Beta 0 (2023-10-19)
### Breaking Changes
* Bump typescript to 5.x
* Remove Node 14 support
* Remove `crypto` polyfills, `create-hash`, `elliptic`, `hash.js`, and their many dependencies in favor of `@noble/hashes` and `@nobel/curves`
* Remove `bip32` and `bip39` in favor of `@scure/bip32` and `@scure/bip39`
* Remove `assert` dependency. If you were catching `AssertionError` you need to change to `Error`
* Configuring a proxy:
* Instead of passing various parameters on the `ConnectionsOptions` you know specify the `agent` parameter. This object can use be created by libraries such as `https-proxy-agent` or any that implements the `http.Agent`.
* This was changed to both support the latest `https-proxy-agent` and to remove the need to include the package in bundlers. Tests will still be done using `https-proxy-agent` and only tested in a node environment which was the only way it was previously supported anyway
* Remove `BroadcastClient` which was deprecated
* Uses `@xrplf/secret-numbers` instead of `xrpl-secret-numbers`
* Improve key algorithm detection. It will now throw Errors with helpful messages
* Move `authorizeChannel` from `wallet/signer` to `wallet/authorizeChannel` to solve a circular dependency issue.
* When using a bundler you must remove the mapping of `ws` to `WSWrapper`. ex. `ws: 'xrpl/dist/npm/client/WSWrapper'`. See [../UNIQUE_STEPS](Unique Steps) for the new, much smaller, configs.
### Bundling Changes
Bundler configurations are much more simplified. See [../UNIQUE_STEPS](Unique Steps) for the new, much smaller, configs.
* removed the following polyfills:
* `assert`
* `crypto-browserify`
* `https-browserify`
* `os-browserify`
* `stream-browserify`
* `stream-http`
* `url`
* `util` - previously added automatically by `webpack`
* `events` - previously added automatically by `webpack` but manual for `vite`
* Removed mappings for:
* `ws` to `WsWrapper`
* Excluding `https-proxy-agent`
### Changed
* Remove `lodash` as a dependency
* Remove many polyfills that were only used for testing in the browser
* Remove `util` from bundle by switching `inspect` to `JSON.stringify`
* Add type for metadata for specific transactions(`Payment`, `NFTokenMint`, `NFTokenCreateOffer`, `NFTokenAcceptOffer`, `NFTokenCancelOffer`)
### Fixed
* Fixed Wallet.generate() ignoring the `algorithm` parameter (Only a problem once binary-codec fix for `derive_keypair` is added)
* Fixed Wallet.fromSeed() ignoring the `algorithm` parameter
* Added pseudo-transaction support to hash functions and response types
## 2.14.1 (2024-02-01)

View File

@@ -1,6 +1,6 @@
{
"name": "xrpl",
"version": "3.0.0",
"version": "4.0.0",
"license": "ISC",
"description": "A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser",
"files": [
@@ -24,17 +24,16 @@
"dependencies": {
"@scure/bip32": "^1.3.1",
"@scure/bip39": "^1.2.1",
"@xrplf/isomorphic": "^1.0.0",
"@xrplf/isomorphic": "^1.0.1",
"@xrplf/secret-numbers": "^1.0.0",
"bignumber.js": "^9.0.0",
"cross-fetch": "^4.0.0",
"eventemitter3": "^5.0.1",
"ripple-address-codec": "^5.0.0",
"ripple-binary-codec": "^2.0.0",
"ripple-binary-codec": "^2.1.0",
"ripple-keypairs": "^2.0.0"
},
"devDependencies": {
"@types/node": "^16.18.38",
"@types/node": "^18.18.38",
"eventemitter3": "^5.0.1",
"https-proxy-agent": "^7.0.1",
"karma": "^6.4.1",
@@ -44,7 +43,7 @@
"lodash": "^4.17.4",
"react": "^18.2.0",
"run-s": "^0.0.0",
"typedoc": "0.25.0",
"typedoc": "0.26.3",
"ws": "^8.14.2"
},
"resolutions": {
@@ -87,6 +86,6 @@
"xrpl"
],
"engines": {
"node": ">=16.0.0"
"node": ">=18.0.0"
}
}

View File

@@ -56,7 +56,7 @@ async function claimPayChannel(): Promise<void> {
Channel: hashes.hashPaymentChannel(
wallet1.classicAddress,
wallet2.classicAddress,
paymentChannelResponse.result.Sequence ?? 0,
paymentChannelResponse.result.tx_json.Sequence ?? 0,
),
Amount: '100',
}

View File

@@ -63,7 +63,7 @@ async function sendEscrow(): Promise<void> {
TransactionType: 'EscrowFinish',
Account: wallet1.classicAddress,
Owner: wallet1.classicAddress,
OfferSequence: Number(createEscrowResponse.result.Sequence),
OfferSequence: Number(createEscrowResponse.result.tx_json.Sequence),
}
await client.submit(finishTx, {

View File

@@ -14,13 +14,11 @@ export interface FaucetWallet {
export enum FaucetNetwork {
Testnet = 'faucet.altnet.rippletest.net',
Devnet = 'faucet.devnet.rippletest.net',
HooksV3Testnet = 'hooks-testnet-v3.xrpl-labs.com',
}
export const FaucetNetworkPaths: Record<string, string> = {
[FaucetNetwork.Testnet]: '/accounts',
[FaucetNetwork.Devnet]: '/accounts',
[FaucetNetwork.HooksV3Testnet]: '/accounts',
}
/**
@@ -33,10 +31,6 @@ export const FaucetNetworkPaths: Record<string, string> = {
export function getFaucetHost(client: Client): FaucetNetwork | undefined {
const connectionUrl = client.url
if (connectionUrl.includes('hooks-testnet-v3')) {
return FaucetNetwork.HooksV3Testnet
}
// 'altnet' for Ripple Testnet server and 'testnet' for XRPL Labs Testnet server
if (connectionUrl.includes('altnet') || connectionUrl.includes('testnet')) {
return FaucetNetwork.Testnet

View File

@@ -1,4 +1,3 @@
import fetch from 'cross-fetch'
import { isValidClassicAddress } from 'ripple-address-codec'
import type { Client } from '../client'

View File

@@ -4,6 +4,7 @@ import {
TimeoutError,
XrplError,
} from '../errors'
import type { APIVersion } from '../models'
import { Response, RequestResponseMap } from '../models/methods'
import { BaseRequest, ErrorResponse } from '../models/methods/baseMethod'
@@ -35,10 +36,10 @@ export default class RequestManager {
* @param timer - The timer associated with the promise.
* @returns A promise that resolves to the specified generic type.
*/
public async addPromise<R extends BaseRequest, T = RequestResponseMap<R>>(
newId: string | number,
timer: ReturnType<typeof setTimeout>,
): Promise<T> {
public async addPromise<
R extends BaseRequest,
T = RequestResponseMap<R, APIVersion>,
>(newId: string | number, timer: ReturnType<typeof setTimeout>): Promise<T> {
return new Promise<T>((resolve, reject) => {
this.promisesAwaitingResponse.set(newId, {
resolve,
@@ -55,7 +56,10 @@ export default class RequestManager {
* @param response - Response to return.
* @throws Error if no existing promise with the given ID.
*/
public resolve(id: string | number, response: Response): void {
public resolve(
id: string | number,
response: Partial<Response<APIVersion>>,
): void {
const promise = this.promisesAwaitingResponse.get(id)
if (promise == null) {
throw new XrplError(`No existing promise with id ${id}`, {
@@ -111,10 +115,10 @@ export default class RequestManager {
* @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<R extends BaseRequest, T = RequestResponseMap<R>>(
request: R,
timeout: number,
): [string | number, string, Promise<T>] {
public createRequest<
R extends BaseRequest,
T = RequestResponseMap<R, APIVersion>,
>(request: R, timeout: number): [string | number, string, Promise<T>] {
let newId: string | number
if (request.id == null) {
newId = this.nextId
@@ -171,7 +175,9 @@ export default class RequestManager {
* @param response - The response to handle.
* @throws ResponseFormatError if the response format is invalid, RippledError if rippled returns an error.
*/
public handleResponse(response: Partial<Response | ErrorResponse>): void {
public handleResponse(
response: Partial<Response<APIVersion> | ErrorResponse>,
): void {
if (
response.id == null ||
!(typeof response.id === 'string' || typeof response.id === 'number')
@@ -205,8 +211,7 @@ export default class RequestManager {
}
// status no longer needed because error is thrown if status is not "success"
delete response.status
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Must be a valid Response here
this.resolve(response.id, response as unknown as Response)
this.resolve(response.id, response)
}
/**

View File

@@ -11,7 +11,7 @@ import {
ConnectionError,
XrplError,
} from '../errors'
import type { RequestResponseMap } from '../models'
import type { APIVersion, RequestResponseMap } from '../models'
import { BaseRequest } from '../models/methods/baseMethod'
import ConnectionManager from './ConnectionManager'
@@ -267,6 +267,7 @@ export class Connection extends EventEmitter {
/**
* Disconnect the websocket, then connect again.
*
*/
public async reconnect(): Promise<void> {
/*
@@ -287,10 +288,10 @@ export class Connection extends EventEmitter {
* @returns The response from the rippled server.
* @throws NotConnectedError if the Connection isn't connected to a server.
*/
public async request<R extends BaseRequest, T = RequestResponseMap<R>>(
request: R,
timeout?: number,
): Promise<T> {
public async request<
R extends BaseRequest,
T = RequestResponseMap<R, APIVersion>,
>(request: R, timeout?: number): Promise<T> {
if (!this.shouldBeConnected || this.ws == null) {
throw new NotConnectedError(JSON.stringify(request), request)
}
@@ -468,6 +469,7 @@ export class Connection extends EventEmitter {
/**
* Starts a heartbeat to check the connection with the server.
*
*/
private startHeartbeatInterval(): void {
this.clearHeartbeatInterval()

View File

@@ -9,7 +9,12 @@ import {
ValidationError,
XrplError,
} from '../errors'
import type { LedgerIndex, Balance } from '../models/common'
import {
APIVersion,
LedgerIndex,
Balance,
DEFAULT_API_VERSION,
} from '../models/common'
import {
Request,
// account methods
@@ -88,8 +93,23 @@ import {
} from './partialPayment'
export interface ClientOptions extends ConnectionUserOptions {
/**
* Multiplication factor to multiply estimated fee by to provide a cushion in case the
* required fee rises during submission of a transaction. Defaults to 1.2.
*
* @category Fee
*/
feeCushion?: number
/**
* Maximum transaction cost to allow, in decimal XRP. Must be a string-encoded
* number. Defaults to '2'.
*
* @category Fee
*/
maxFeeXRP?: string
/**
* Duration to wait for a request to timeout.
*/
timeout?: number
}
@@ -198,6 +218,12 @@ class Client extends EventEmitter<EventTypes> {
*/
public buildVersion: string | undefined
/**
* API Version used by the server this client is connected to
*
*/
public apiVersion: APIVersion = DEFAULT_API_VERSION
/**
* Creates a new Client with a websocket connection to a rippled server.
*
@@ -211,7 +237,7 @@ class Client extends EventEmitter<EventTypes> {
* const client = new Client('wss://s.altnet.rippletest.net:51233')
* ```
*/
// eslint-disable-next-line max-lines-per-function -- okay because we have to set up all the connection handlers
/* eslint-disable max-lines-per-function -- the constructor requires more lines to implement the logic */
public constructor(server: string, options: ClientOptions = {}) {
super()
if (typeof server !== 'string' || !/wss?(?:\+unix)?:\/\//u.exec(server)) {
@@ -275,6 +301,7 @@ class Client extends EventEmitter<EventTypes> {
this.emit('path_find', path)
})
}
/* eslint-enable max-lines-per-function */
/**
* Get the url that the client is connected to.
@@ -291,7 +318,6 @@ class Client extends EventEmitter<EventTypes> {
* additional request body parameters.
*
* @category Network
*
* @param req - Request to send to the server.
* @returns The response from the server.
*
@@ -304,16 +330,20 @@ class Client extends EventEmitter<EventTypes> {
* console.log(response)
* ```
*/
public async request<R extends Request, T = RequestResponseMap<R>>(
req: R,
): Promise<T> {
const response = await this.connection.request<R, T>({
public async request<
R extends Request,
V extends APIVersion = typeof DEFAULT_API_VERSION,
T = RequestResponseMap<R, V>,
>(req: R): Promise<T> {
const request = {
...req,
account: req.account
? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Must be string
ensureClassicAddress(req.account as string)
: undefined,
})
account:
typeof req.account === 'string'
? ensureClassicAddress(req.account)
: undefined,
api_version: req.api_version ?? this.apiVersion,
}
const response = await this.connection.request<R, T>(request)
// mutates `response` to add warnings
handlePartialPayment(req.command, response)
@@ -422,9 +452,10 @@ class Client extends EventEmitter<EventTypes> {
* const allResponses = await client.requestAll({ command: 'transaction_data' });
* console.log(allResponses);
*/
public async requestAll<
T extends MarkerRequest,
U = RequestAllResponseMap<T>,
U = RequestAllResponseMap<T, APIVersion>,
>(request: T, collect?: string): Promise<U[]> {
/*
* The data under collection is keyed based on the command. Fail if command
@@ -441,7 +472,6 @@ class Client extends EventEmitter<EventTypes> {
const countTo: number = request.limit == null ? Infinity : request.limit
let count = 0
let marker: unknown = request.marker
let lastBatchLength: number
const results: U[] = []
do {
const countRemaining = clamp(countTo - count, MIN_LIMIT, MAX_LIMIT)
@@ -453,7 +483,7 @@ class Client extends EventEmitter<EventTypes> {
// eslint-disable-next-line no-await-in-loop -- Necessary for this, it really has to wait
const singleResponse = await this.connection.request(repeatProps)
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Should be true
const singleResult = (singleResponse as MarkerResponse).result
const singleResult = (singleResponse as MarkerResponse<APIVersion>).result
if (!(collectKey in singleResult)) {
throw new XrplError(`${collectKey} not in result`)
}
@@ -465,11 +495,8 @@ class Client extends EventEmitter<EventTypes> {
// Make sure we handle when no data (not even an empty array) is returned.
if (Array.isArray(collectedData)) {
count += collectedData.length
lastBatchLength = collectedData.length
} else {
lastBatchLength = 0
}
} while (Boolean(marker) && count < countTo && lastBatchLength !== 0)
} while (Boolean(marker) && count < countTo)
return results
}
@@ -627,7 +654,10 @@ class Client extends EventEmitter<EventTypes> {
* @param signersCount - The expected number of signers for this transaction.
* Only used for multisigned transactions.
* @returns The autofilled transaction.
* @throws ValidationError If Amount and DeliverMax fields are not identical in a Payment Transaction
*/
// eslint-disable-next-line complexity -- handling Payment transaction API v2 requires more logic
public async autofill<T extends SubmittableTransaction>(
transaction: T,
signersCount?: number,
@@ -635,7 +665,6 @@ class Client extends EventEmitter<EventTypes> {
const tx = { ...transaction }
setValidAddresses(tx)
setTransactionFlagsToNumber(tx)
const promises: Array<Promise<void>> = []
@@ -655,6 +684,34 @@ class Client extends EventEmitter<EventTypes> {
promises.push(checkAccountDeleteBlockers(this, tx))
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property
// @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level
if (tx.TransactionType === 'Payment' && tx.DeliverMax != null) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- This is a valid null check for Amount
if (tx.Amount == null) {
// If only DeliverMax is provided, use it to populate the Amount field
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property
// @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- DeliverMax is a known RPC-level property
tx.Amount = tx.DeliverMax
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property
// @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- This is a valid null check for Amount
if (tx.Amount != null && tx.Amount !== tx.DeliverMax) {
return Promise.reject(
new ValidationError(
'PaymentTransaction: Amount and DeliverMax fields must be identical when both are provided',
),
)
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property
// @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level
delete tx.DeliverMax
}
return Promise.all(promises).then(() => tx)
}
@@ -898,7 +955,7 @@ class Client extends EventEmitter<EventTypes> {
* @param options.limit - Limit number of balances to return.
* @returns An array of XRP/non-XRP balances for the given account.
*/
// eslint-disable-next-line max-lines-per-function -- Longer definition is required for end users to see the definition.
/* eslint-disable max-lines-per-function -- getBalances requires more lines to implement logic */
public async getBalances(
address: string,
options: {
@@ -946,6 +1003,7 @@ class Client extends EventEmitter<EventTypes> {
)
return balances.slice(0, options.limit)
}
/* eslint-enable max-lines-per-function */
/**
* Fetch orderbook (buy/sell orders) between two currency pairs. This checks both sides of the orderbook

View File

@@ -2,13 +2,16 @@ import BigNumber from 'bignumber.js'
import { decode } from 'ripple-binary-codec'
import type {
AccountTxResponse,
TransactionEntryResponse,
TransactionStream,
TxResponse,
} from '..'
import type { Amount } from '../models/common'
import type { RequestResponseMap } from '../models/methods'
import type { Amount, APIVersion, DEFAULT_API_VERSION } from '../models/common'
import type {
AccountTxTransaction,
RequestResponseMap,
} from '../models/methods'
import { AccountTxVersionResponseMap } from '../models/methods/accountTx'
import { BaseRequest, BaseResponse } from '../models/methods/baseMethod'
import { PaymentFlags, Transaction } from '../models/transactions'
import type { TransactionMetadata } from '../models/transactions/metadata'
@@ -63,7 +66,10 @@ function isPartialPayment(
}
const delivered = meta.delivered_amount
const amount = tx.Amount
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- DeliverMax is a valid field on Payment response
// @ts-expect-error -- DeliverMax is a valid field on Payment response
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- DeliverMax is a valid field on Payment response
const amount = tx.DeliverMax
if (delivered === undefined) {
return false
@@ -73,23 +79,36 @@ function isPartialPayment(
}
function txHasPartialPayment(response: TxResponse): boolean {
return isPartialPayment(response.result, response.result.meta)
return isPartialPayment(response.result.tx_json, response.result.meta)
}
function txEntryHasPartialPayment(response: TransactionEntryResponse): boolean {
return isPartialPayment(response.result.tx_json, response.result.metadata)
}
function accountTxHasPartialPayment(response: AccountTxResponse): boolean {
function accountTxHasPartialPayment<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
>(response: AccountTxVersionResponseMap<Version>): boolean {
const { transactions } = response.result
const foo = transactions.some((tx) => isPartialPayment(tx.tx, tx.meta))
const foo = transactions.some((tx) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- required to check API version model
if (tx.tx_json != null) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- use API v2 model
const transaction = tx as AccountTxTransaction
return isPartialPayment(transaction.tx_json, transaction.meta)
}
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- use API v1 model
const transaction = tx as AccountTxTransaction<1>
return isPartialPayment(transaction.tx, transaction.meta)
})
return foo
}
function hasPartialPayment<R extends BaseRequest, T = RequestResponseMap<R>>(
command: string,
response: T,
): boolean {
function hasPartialPayment<
R extends BaseRequest,
V extends APIVersion = typeof DEFAULT_API_VERSION,
T = RequestResponseMap<R, V>,
>(command: string, response: T): boolean {
/* eslint-disable @typescript-eslint/consistent-type-assertions -- Request type is known at runtime from command */
switch (command) {
case 'tx':
@@ -97,7 +116,9 @@ function hasPartialPayment<R extends BaseRequest, T = RequestResponseMap<R>>(
case 'transaction_entry':
return txEntryHasPartialPayment(response as TransactionEntryResponse)
case 'account_tx':
return accountTxHasPartialPayment(response as AccountTxResponse)
return accountTxHasPartialPayment(
response as AccountTxVersionResponseMap<V>,
)
default:
return false
}
@@ -112,7 +133,7 @@ function hasPartialPayment<R extends BaseRequest, T = RequestResponseMap<R>>(
*/
export function handlePartialPayment<
R extends BaseRequest,
T = RequestResponseMap<R>,
T = RequestResponseMap<R, APIVersion>,
>(command: string, response: T): void {
if (hasPartialPayment(command, response)) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We are checking dynamically and safely.

View File

@@ -1,3 +1,7 @@
export const RIPPLED_API_V1 = 1
export const RIPPLED_API_V2 = 2
export const DEFAULT_API_VERSION = RIPPLED_API_V2
export type APIVersion = typeof RIPPLED_API_V1 | typeof RIPPLED_API_V2
export type LedgerIndex = number | ('validated' | 'closed' | 'current')
export interface XRP {
@@ -104,6 +108,10 @@ export interface ResponseOnlyTxInfo {
* The sequence number of the ledger that included this transaction.
*/
ledger_index?: number
/**
* The hash of the ledger included this transaction.
*/
ledger_hash?: string
/**
* @deprecated Alias for ledger_index.
*/
@@ -155,3 +163,36 @@ export interface XChainBridge {
IssuingChainDoor: string
IssuingChainIssue: Currency
}
/**
* A PriceData object represents the price information for a token pair.
*
*/
export interface PriceData {
PriceData: {
/**
* The primary asset in a trading pair. Any valid identifier, such as a stock symbol, bond CUSIP, or currency code is allowed.
* For example, in the BTC/USD pair, BTC is the base asset; in 912810RR9/BTC, 912810RR9 is the base asset.
*/
BaseAsset: string
/**
* The quote asset in a trading pair. The quote asset denotes the price of one unit of the base asset. For example, in the
* BTC/USD pair,BTC is the base asset; in 912810RR9/BTC, 912810RR9 is the base asset.
*/
QuoteAsset: string
/**
* The asset price after applying the Scale precision level. It's not included if the last update transaction didn't include
* the BaseAsset/QuoteAsset pair.
*/
AssetPrice?: number | string
/**
* The scaling factor to apply to an asset price. For example, if Scale is 6 and original price is 0.155, then the scaled
* price is 155000. Valid scale ranges are 0-10. It's not included if the last update transaction didn't include the
* BaseAsset/QuoteAsset pair.
*/
Scale?: number
}
}

View File

@@ -1,6 +1,6 @@
import { AuthAccount, Currency, IssuedCurrencyAmount } from '../common'
import { BaseLedgerEntry, MissingPreviousTxnID } from './BaseLedgerEntry'
import { BaseLedgerEntry, HasOptionalPreviousTxnID } from './BaseLedgerEntry'
export interface VoteSlot {
VoteEntry: {
@@ -15,7 +15,7 @@ export interface VoteSlot {
*
* @category Ledger Entries
*/
export default interface AMM extends BaseLedgerEntry, MissingPreviousTxnID {
export default interface AMM extends BaseLedgerEntry, HasOptionalPreviousTxnID {
LedgerEntryType: 'AMM'
/**
* The address of the special account that holds this AMM's assets.

View File

@@ -1,4 +1,4 @@
import { BaseLedgerEntry, MissingPreviousTxnID } from './BaseLedgerEntry'
import { BaseLedgerEntry, HasOptionalPreviousTxnID } from './BaseLedgerEntry'
/**
* The unique id for the Amendments object https://xrpl.org/amendments-object.html#amendments-id-format
@@ -26,7 +26,7 @@ export interface Majority {
*/
export default interface Amendments
extends BaseLedgerEntry,
MissingPreviousTxnID {
HasOptionalPreviousTxnID {
LedgerEntryType: 'Amendments'
/**
* Array of 256-bit amendment IDs for all currently-enabled amendments. If

View File

@@ -15,13 +15,17 @@ export interface HasPreviousTxnID {
PreviousTxnLgrSeq: number
}
export interface MissingPreviousTxnID {
export interface HasOptionalPreviousTxnID {
/**
* This field is missing on this object but is present on most other returned objects.
* The identifying hash of the transaction that most recently modified this
* object. This field was added in the `fixPreviousTxnID` amendment, so it
* may not be present in every object.
*/
PreviousTxnID: never
PreviousTxnID?: string
/**
* This field is missing on this object but is present on most other returned objects.
* The index of the ledger that contains the transaction that most recently
* modified this object. This field was added in the `fixPreviousTxnID`
* amendment, so it may not be present in every object.
*/
PreviousTxnLgrSeq: never
PreviousTxnLgrSeq?: number
}

View File

@@ -1,4 +1,4 @@
import { BaseLedgerEntry, MissingPreviousTxnID } from './BaseLedgerEntry'
import { BaseLedgerEntry, HasOptionalPreviousTxnID } from './BaseLedgerEntry'
/**
* The DirectoryNode object type provides a list of links to other objects in
@@ -8,7 +8,7 @@ import { BaseLedgerEntry, MissingPreviousTxnID } from './BaseLedgerEntry'
*/
export default interface DirectoryNode
extends BaseLedgerEntry,
MissingPreviousTxnID {
HasOptionalPreviousTxnID {
LedgerEntryType: 'DirectoryNode'
/**
* A bit-map of boolean flags enabled for this directory. Currently, the

View File

@@ -1,4 +1,4 @@
import { BaseLedgerEntry, MissingPreviousTxnID } from './BaseLedgerEntry'
import { BaseLedgerEntry, HasOptionalPreviousTxnID } from './BaseLedgerEntry'
/**
* The unique id for the FeeSettings object https://xrpl.org/feesettings.html#feesettings-id-format
@@ -26,7 +26,9 @@ export interface FeeSettingsPostAmendmentFields {
ReserveIncrementDrops: string
}
export interface FeeSettingsBase extends BaseLedgerEntry, MissingPreviousTxnID {
export interface FeeSettingsBase
extends BaseLedgerEntry,
HasOptionalPreviousTxnID {
LedgerEntryType: 'FeeSettings'
/**
* A bit-map of boolean flags for this object. No flags are defined for this type.

View File

@@ -1,14 +1,14 @@
import { APIVersion, DEFAULT_API_VERSION, RIPPLED_API_V1 } from '../common'
import { Transaction, TransactionMetadata } from '../transactions'
import { LedgerEntry } from './LedgerEntry'
/**
* A ledger is a block of transactions and shared state data. It has a unique
* header that describes its contents using cryptographic hashes.
* Common properties for ledger entries.
*
* @category Ledger Entries
*/
export default interface Ledger {
interface BaseLedger {
/** The SHA-512Half of this ledger's state tree information. */
account_hash: string
/** All the state information in this ledger. Admin only. */
@@ -38,11 +38,6 @@ export default interface Ledger {
* for this ledger and all its contents.
*/
ledger_hash: string
/**
* The ledger index of the ledger. Some API methods display this as a quoted
* integer; some display it as a native JSON number.
*/
ledger_index: string
/** The approximate time at which the previous ledger was closed. */
parent_close_time: number
/**
@@ -61,5 +56,47 @@ export default interface Ledger {
* either JSON or binary depending on whether the request specified binary
* as true.
*/
transactions?: Array<Transaction & { metaData?: TransactionMetadata }>
transactions?: Array<
Transaction & {
hash: string
metaData?: TransactionMetadata
}
>
}
/**
* A ledger is a block of transactions and shared state data. It has a unique
* header that describes its contents using cryptographic hashes.
*
* @category Ledger Entries
*/
export interface Ledger extends BaseLedger {
/**
* The ledger index of the ledger. Represented as a number.
*/
ledger_index: number
}
/**
* A ledger is a block of transactions and shared state data. It has a unique
* header that describes its contents using cryptographic hashes. This is used
* in api_version 1.
*
* @category Ledger Entries
*/
export interface LedgerV1 extends BaseLedger {
/**
* The ledger index of the ledger. Some API methods display this as a quoted
* integer; some display it as a number.
*/
ledger_index: string
}
/**
* Type to map between the API version and the Ledger type.
*
* @category Responses
*/
export type LedgerVersionMap<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = Version extends typeof RIPPLED_API_V1 ? LedgerV1 : Ledger

View File

@@ -10,6 +10,7 @@ import FeeSettings from './FeeSettings'
import LedgerHashes from './LedgerHashes'
import NegativeUNL from './NegativeUNL'
import Offer from './Offer'
import Oracle from './Oracle'
import PayChannel from './PayChannel'
import RippleState from './RippleState'
import SignerList from './SignerList'
@@ -30,6 +31,7 @@ type LedgerEntry =
| LedgerHashes
| NegativeUNL
| Offer
| Oracle
| PayChannel
| RippleState
| SignerList
@@ -52,6 +54,7 @@ type LedgerEntryFilter =
| 'nft_offer'
| 'nft_page'
| 'offer'
| 'oracle'
| 'payment_channel'
| 'signer_list'
| 'state'

View File

@@ -1,4 +1,4 @@
import { BaseLedgerEntry, MissingPreviousTxnID } from './BaseLedgerEntry'
import { BaseLedgerEntry } from './BaseLedgerEntry'
/**
* The LedgerHashes objects exist to make it possible to look up a previous
@@ -7,9 +7,7 @@ import { BaseLedgerEntry, MissingPreviousTxnID } from './BaseLedgerEntry'
*
* @category Ledger Entries
*/
export default interface LedgerHashes
extends BaseLedgerEntry,
MissingPreviousTxnID {
export default interface LedgerHashes extends BaseLedgerEntry {
LedgerEntryType: 'LedgerHashes'
/** The Ledger Index of the last entry in this object's Hashes array. */
LastLedgerSequence?: number

View File

@@ -1,4 +1,4 @@
import { BaseLedgerEntry, MissingPreviousTxnID } from './BaseLedgerEntry'
import { BaseLedgerEntry, HasOptionalPreviousTxnID } from './BaseLedgerEntry'
/**
* The unique id for the nUNL object https://xrpl.org/negativeunl.html#negativeunl-id-format
@@ -14,7 +14,7 @@ export const NEGATIVE_UNL_ID =
*/
export default interface NegativeUNL
extends BaseLedgerEntry,
MissingPreviousTxnID {
HasOptionalPreviousTxnID {
LedgerEntryType: 'NegativeUNL'
/**
* A list of trusted validators that are currently disabled.

View File

@@ -0,0 +1,43 @@
import { PriceData } from '../common'
import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'
/**
* The Oracle object type describes a single Price Oracle instance.
*
* @category Ledger Entries
*/
export default interface Oracle extends BaseLedgerEntry, HasPreviousTxnID {
LedgerEntryType: 'Oracle'
/**
* The time the data was last updated, represented as a unix timestamp in seconds.
*/
LastUpdateTime: number
/**
* The XRPL account with update and delete privileges for the oracle.
*/
Owner: string
/**
* Describes the type of asset, such as "currency", "commodity", or "index".
*/
AssetClass: string
/**
* The oracle provider, such as Chainlink, Band, or DIA.
*/
Provider: string
/**
* An array of up to 10 PriceData objects.
*/
PriceDataSeries: PriceData[]
/**
* A bit-map of boolean flags. No flags are defined for the Oracle object
* type, so this value is always 0.
*/
Flags: 0
}

View File

@@ -75,4 +75,6 @@ export enum RippleStateFlags {
lsfLowFreeze = 0x00400000,
// True, high side has set freeze flag
lsfHighFreeze = 0x00800000,
// True, trust line to AMM. Used by client apps to identify payments via AMM.
lsfAMMNode = 0x01000000,
}

View File

@@ -15,13 +15,14 @@ import FeeSettings, {
FeeSettingsPostAmendmentFields,
FEE_SETTINGS_ID,
} from './FeeSettings'
import Ledger from './Ledger'
import { Ledger, LedgerV1 } from './Ledger'
import { LedgerEntry, LedgerEntryFilter } from './LedgerEntry'
import LedgerHashes from './LedgerHashes'
import NegativeUNL, { NEGATIVE_UNL_ID } from './NegativeUNL'
import { NFTokenOffer } from './NFTokenOffer'
import { NFToken, NFTokenPage } from './NFTokenPage'
import Offer, { OfferFlags } from './Offer'
import Oracle from './Oracle'
import PayChannel from './PayChannel'
import RippleState, { RippleStateFlags } from './RippleState'
import SignerList, { SignerListFlags } from './SignerList'
@@ -47,6 +48,7 @@ export {
FeeSettingsPreAmendmentFields,
FeeSettingsPostAmendmentFields,
Ledger,
LedgerV1,
LedgerEntryFilter,
LedgerEntry,
LedgerHashes,
@@ -58,6 +60,7 @@ export {
NFToken,
Offer,
OfferFlags,
Oracle,
PayChannel,
RippleState,
RippleStateFlags,

View File

@@ -1,17 +1,80 @@
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
/**
* Represents a payment channel in the XRP Ledger.
*/
export interface Channel {
/** The owner of the channel, as an Address. */
account: string
/** The total amount of XRP, in drops allocated to this channel. */
amount: string
/**
* The total amount of XRP, in drops, paid out from this channel,
* as of the ledger version used. (You can calculate the amount of
* XRP left in the channel by subtracting balance from amount.)
*/
balance: string
/**
* A unique ID for this channel, as a 64-character hexadecimal string.
* This is also the ID of the channel object in the ledger's state data.
*/
channel_id: string
/**
* The destination account of the channel, as an Address.
* Only this account can receive the XRP in the channel while it is open.
*/
destination_account: string
/**
* The number of seconds the payment channel must stay open after the owner
* of the channel requests to close it.
*/
settle_delay: number
/**
* The public key for the payment channel in the XRP Ledger's base58 format.
* Signed claims against this channel must be redeemed with the matching key pair.
*/
public_key?: string
/**
* The public key for the payment channel in hexadecimal format, if one was
* specified at channel creation. Signed claims against this channel must be
* redeemed with the matching key pair.
*/
public_key_hex?: string
/**
* Time, in seconds since the Ripple Epoch, when this channel is set to expire.
* This expiration date is mutable. If this is before the close time of the most
* recent validated ledger, the channel is expired.
*/
expiration?: number
/**
* Time, in seconds since the Ripple Epoch, of this channel's immutable expiration,
* if one was specified at channel creation. If this is before the close time of the
* most recent validated ledger, the channel is expired.
*/
cancel_after?: number
source_tab?: number
/**
* A 32-bit unsigned integer to use as a source tag for payments through this payment channel,
* if one was specified at channel creation. This indicates the payment channel's originator or
* other purpose at the source account. Conventionally, if you bounce payments from this channel,
* you should specify this value in the DestinationTag of the return payment.
*/
source_tag?: number
/**
* A 32-bit unsigned integer to use as a destination tag for payments through this channel,
* if one was specified at channel creation. This indicates the payment channel's beneficiary
* or other purpose at the destination account.
*/
destination_tag?: number
}

View File

@@ -1,3 +1,4 @@
import { APIVersion, DEFAULT_API_VERSION, RIPPLED_API_V1 } from '../common'
import { AccountRoot, SignerList } from '../ledger'
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
@@ -133,23 +134,13 @@ export interface AccountInfoAccountFlags {
allowTrustLineClawback: boolean
}
/**
* Response expected from an {@link AccountInfoRequest}.
*
* @category Responses
*/
export interface AccountInfoResponse extends BaseResponse {
interface BaseAccountInfoResponse extends BaseResponse {
result: {
/**
* The AccountRoot ledger object with this account's information, as stored
* in the ledger.
* If requested, also includes Array of SignerList ledger objects
* associated with this account for Multi-Signing. Since an account can own
* at most one SignerList, this array must have exactly one member if it is
* present.
*/
account_data: AccountRoot & { signer_lists?: SignerList[] }
account_data: AccountRoot
/**
* A map of account flags parsed out. This will only be available for rippled nodes 1.11.0 and higher.
*/
@@ -180,3 +171,58 @@ export interface AccountInfoResponse extends BaseResponse {
validated?: boolean
}
}
/**
* Response expected from a {@link AccountInfoRequest}.
*
* @category Responses
*/
export interface AccountInfoResponse extends BaseAccountInfoResponse {
result: BaseAccountInfoResponse['result'] & {
/**
* If requested, array of SignerList ledger objects associated with this account for Multi-Signing.
* Since an account can own at most one SignerList, this array must have exactly one
* member if it is present.
*/
signer_lists?: SignerList[]
}
}
/**
* Response expected from a {@link AccountInfoRequest} using API version 1.
*
* @category ResponsesV1
*/
export interface AccountInfoV1Response extends BaseAccountInfoResponse {
result: BaseAccountInfoResponse['result'] & {
/**
* The AccountRoot ledger object with this account's information, as stored
* in the ledger.
* If requested, also includes Array of SignerList ledger objects
* associated with this account for Multi-Signing. Since an account can own
* at most one SignerList, this array must have exactly one member if it is
* present.
*/
account_data: BaseAccountInfoResponse['result']['account_data'] & {
/**
* Array of SignerList ledger objects associated with this account for Multi-Signing.
* Since an account can own at most one SignerList, this array must have exactly one
* member if it is present.
* Quirk: In API version 1, this field is nested under account_data. For this method,
* Clio implements the API version 2 behavior where is field is not nested under account_data.
*/
signer_lists?: SignerList[]
}
}
}
/**
* Type to map between the API version and the response type.
*
* @category Responses
*/
export type AccountInfoVersionResponseMap<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = Version extends typeof RIPPLED_API_V1
? AccountInfoV1Response
: AccountInfoResponse

View File

@@ -1,4 +1,10 @@
import { ResponseOnlyTxInfo } from '../common'
import {
APIVersion,
DEFAULT_API_VERSION,
RIPPLED_API_V1,
RIPPLED_API_V2,
ResponseOnlyTxInfo,
} from '../common'
import { Transaction, TransactionMetadata } from '../transactions'
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
@@ -49,7 +55,9 @@ export interface AccountTxRequest extends BaseRequest, LookupByLedgerRequest {
marker?: unknown
}
export interface AccountTxTransaction {
export interface AccountTxTransaction<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> {
/** The ledger index of the ledger version that included this transaction. */
ledger_index: number
/**
@@ -58,7 +66,15 @@ export interface AccountTxTransaction {
*/
meta: string | TransactionMetadata
/** JSON object defining the transaction. */
tx?: Transaction & ResponseOnlyTxInfo
tx_json?: Version extends typeof RIPPLED_API_V2
? Transaction & ResponseOnlyTxInfo
: never
/** JSON object defining the transaction in rippled API v1. */
tx?: Version extends typeof RIPPLED_API_V1
? Transaction & ResponseOnlyTxInfo
: never
/** The hash of the transaction. */
hash?: Version extends typeof RIPPLED_API_V2 ? string : never
/** Unique hashed String representing the transaction. */
tx_blob?: string
/**
@@ -69,11 +85,11 @@ export interface AccountTxTransaction {
}
/**
* Expected response from an {@link AccountTxRequest}.
*
* @category Responses
* Base interface for account transaction responses.
*/
export interface AccountTxResponse extends BaseResponse {
interface AccountTxResponseBase<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> extends BaseResponse {
result: {
/** Unique Address identifying the related account. */
account: string
@@ -98,7 +114,7 @@ export interface AccountTxResponse extends BaseResponse {
* Array of transactions matching the request's criteria, as explained
* below.
*/
transactions: AccountTxTransaction[]
transactions: Array<AccountTxTransaction<Version>>
/**
* If included and set to true, the information in this response comes from
* a validated ledger version. Otherwise, the information is subject to
@@ -107,3 +123,28 @@ export interface AccountTxResponse extends BaseResponse {
validated?: boolean
}
}
/**
* Expected response from an {@link AccountTxRequest}.
*
* @category Responses
*/
export type AccountTxResponse = AccountTxResponseBase
/**
* Expected response from an {@link AccountTxRequest} with `api_version` set to 1.
*
* @category ResponsesV1
*/
export type AccountTxV1Response = AccountTxResponseBase<typeof RIPPLED_API_V1>
/**
* Type to map between the API version and the response type.
*
* @category Responses
*/
export type AccountTxVersionResponseMap<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = Version extends typeof RIPPLED_API_V1
? AccountTxV1Response
: AccountTxResponse

View File

@@ -0,0 +1,68 @@
import { BaseRequest, BaseResponse } from './baseMethod'
export interface FeatureAllRequest extends BaseRequest {
command: 'feature'
feature?: never
}
export interface FeatureOneRequest extends BaseRequest {
command: 'feature'
feature: string
}
/**
* The `feature` command returns information about amendments this server knows about, including whether they are enabled.
* Returns an {@link FeatureResponse}.
*
* @category Requests
*/
export type FeatureRequest = FeatureAllRequest | FeatureOneRequest
export interface FeatureAllResponse extends BaseResponse {
result: {
features: Record<
string,
{
/*
* Whether this amendment is currently enabled in the latest ledger.
*/
enabled: boolean
/*
* The human-readable name for this amendment, if known.
*/
name: string
supported: boolean
}
>
}
}
export interface FeatureOneResponse extends BaseResponse {
result: Record<
string,
{
/*
* Whether this amendment is currently enabled in the latest ledger.
*/
enabled: boolean
/*
* The human-readable name for this amendment, if known.
*/
name: string
supported: boolean
}
>
}
/**
* Response expected from an {@link FeatureRequest}.
*
* @category Responses
*/
export type FeatureResponse = FeatureAllResponse | FeatureOneResponse

View File

@@ -0,0 +1,119 @@
import { BaseRequest, BaseResponse } from './baseMethod'
/**
* The `get_aggregate_price` method retrieves the aggregate price of specified Oracle objects,
* returning three price statistics: mean, median, and trimmed mean.
* Returns an {@link GetAggregatePriceResponse}.
*
* @category Requests
*/
export interface GetAggregatePriceRequest extends BaseRequest {
command: 'get_aggregate_price'
/**
* The currency code of the asset to be priced.
*/
base_asset: string
/**
* The currency code of the asset to quote the price of the base asset.
*/
quote_asset: string
/**
* The oracle identifier.
*/
oracles: Array<{
/**
* The XRPL account that controls the Oracle object.
*/
account: string
/**
* A unique identifier of the price oracle for the Account
*/
oracle_document_id: string | number
}>
/**
* The percentage of outliers to trim. Valid trim range is 1-25. If included, the API returns statistics for the trimmed mean.
*/
trim?: number
/**
* Defines a time range in seconds for filtering out older price data. Default value is 0, which doesn't filter any data.
*/
trim_threshold?: number
}
/**
* Response expected from an {@link GetAggregatePriceRequest}.
*
* @category Responses
*/
export interface GetAggregatePriceResponse extends BaseResponse {
result: {
/**
* The statistics from the collected oracle prices.
*/
entire_set: {
/**
* The simple mean.
*/
mean: string
/**
* The size of the data set to calculate the mean.
*/
size: number
/**
* The standard deviation.
*/
standard_deviation: string
}
/**
* The trimmed statistics from the collected oracle prices. Only appears if the trim field was specified in the request.
*/
trimmed_set?: {
/**
* The simple mean of the trimmed data.
*/
mean: string
/**
* The size of the data to calculate the trimmed mean.
*/
size: number
/**
* The standard deviation of the trimmed data.
*/
standard_deviation: string
}
/**
* The median of the collected oracle prices.
*/
median: string
/**
* The most recent timestamp out of all LastUpdateTime values.
*/
time: number
/**
* The ledger index of the ledger version that was used to generate this
* response.
*/
ledger_current_index: number
/**
* If included and set to true, the information in this response comes from
* a validated ledger version. Otherwise, the information is subject to
* change.
*/
validated: boolean
}
}

View File

@@ -1,5 +1,7 @@
/* eslint-disable no-inline-comments -- Necessary for important note */
/* eslint-disable max-lines -- There is a lot to export */
import type { APIVersion, DEFAULT_API_VERSION } from '../common'
import {
AccountChannelsRequest,
AccountChannelsResponse,
@@ -13,6 +15,8 @@ import {
AccountInfoAccountFlags,
AccountInfoRequest,
AccountInfoResponse,
AccountInfoV1Response,
AccountInfoVersionResponseMap,
AccountQueueData,
AccountQueueTransaction,
} from './accountInfo'
@@ -40,6 +44,8 @@ import {
import {
AccountTxRequest,
AccountTxResponse,
AccountTxV1Response,
AccountTxVersionResponseMap,
AccountTxTransaction,
} from './accountTx'
import { AMMInfoRequest, AMMInfoResponse } from './ammInfo'
@@ -60,23 +66,37 @@ import {
DepositAuthorizedRequest,
DepositAuthorizedResponse,
} from './depositAuthorized'
import {
FeatureAllRequest,
FeatureAllResponse,
FeatureOneRequest,
FeatureOneResponse,
FeatureRequest,
FeatureResponse,
} from './feature'
import { FeeRequest, FeeResponse } from './fee'
import {
GatewayBalance,
GatewayBalancesRequest,
GatewayBalancesResponse,
} from './gatewayBalances'
import {
GetAggregatePriceRequest,
GetAggregatePriceResponse,
} from './getAggregatePrice'
import {
LedgerBinary,
LedgerModifiedOfferCreateTransaction,
LedgerQueueData,
LedgerRequest,
LedgerResponse,
LedgerV1Response,
LedgerRequestExpandedTransactionsOnly,
LedgerResponseExpanded,
LedgerRequestExpandedAccountsAndTransactions,
LedgerRequestExpandedAccountsOnly,
LedgerRequestExpandedTransactionsBinary,
LedgerVersionResponseMap,
} from './ledger'
import { LedgerClosedRequest, LedgerClosedResponse } from './ledgerClosed'
import { LedgerCurrentRequest, LedgerCurrentResponse } from './ledgerCurrent'
@@ -96,6 +116,7 @@ import {
NFTHistoryTransaction,
} from './nftHistory'
import { NFTInfoRequest, NFTInfoResponse } from './nftInfo'
import { NFTsByIssuerRequest, NFTsByIssuerResponse } from './nftsByIssuer'
import { NFTSellOffersRequest, NFTSellOffersResponse } from './nftSellOffers'
import { NoRippleCheckRequest, NoRippleCheckResponse } from './norippleCheck'
import {
@@ -131,6 +152,8 @@ import { SubmitRequest, SubmitResponse } from './submit'
import {
SubmitMultisignedRequest,
SubmitMultisignedResponse,
SubmitMultisignedV1Response,
SubmitMultisignedVersionResponseMap,
} from './submitMultisigned'
import {
BooksSnapshot,
@@ -151,7 +174,7 @@ import {
TransactionEntryRequest,
TransactionEntryResponse,
} from './transactionEntry'
import { TxRequest, TxResponse } from './tx'
import { TxRequest, TxResponse, TxV1Response, TxVersionResponseMap } from './tx'
import {
UnsubscribeBook,
UnsubscribeRequest,
@@ -199,6 +222,7 @@ type Request =
| ServerDefinitionsRequest
| ServerInfoRequest
| ServerStateRequest
| FeatureRequest
// utility methods
| PingRequest
| RandomRequest
@@ -208,33 +232,36 @@ type Request =
// clio only methods
| NFTInfoRequest
| NFTHistoryRequest
| NFTsByIssuerRequest
// AMM methods
| AMMInfoRequest
// Price Oracle methods
| GetAggregatePriceRequest
/**
* @category Responses
*/
type Response =
type Response<Version extends APIVersion = typeof DEFAULT_API_VERSION> =
// account methods
| AccountChannelsResponse
| AccountCurrenciesResponse
| AccountInfoResponse
| AccountInfoVersionResponseMap<Version>
| AccountLinesResponse
| AccountNFTsResponse
| AccountObjectsResponse
| AccountOffersResponse
| AccountTxResponse
| AccountTxVersionResponseMap<Version>
| GatewayBalancesResponse
| NoRippleCheckResponse
// ledger methods
| LedgerResponse
| LedgerVersionResponseMap<Version>
| LedgerClosedResponse
| LedgerCurrentResponse
| LedgerDataResponse
| LedgerEntryResponse
// transaction methods
| SubmitResponse
| SubmitMultisignedResponse
| SubmitMultisignedVersionResponseMap<Version>
| TransactionEntryResponse
| TxResponse
// path and order book methods
@@ -253,6 +280,7 @@ type Response =
| ServerDefinitionsResponse
| ServerInfoResponse
| ServerStateResponse
| FeatureResponse
// utility methods
| PingResponse
| RandomResponse
@@ -262,15 +290,21 @@ type Response =
// clio only methods
| NFTInfoResponse
| NFTHistoryResponse
| NFTsByIssuerResponse
// AMM methods
| AMMInfoResponse
// Price Oracle methods
| GetAggregatePriceResponse
export type RequestResponseMap<T> = T extends AccountChannelsRequest
export type RequestResponseMap<
T,
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = T extends AccountChannelsRequest
? AccountChannelsResponse
: T extends AccountCurrenciesRequest
? AccountCurrenciesResponse
: T extends AccountInfoRequest
? AccountInfoResponse
? AccountInfoVersionResponseMap<Version>
: T extends AccountLinesRequest
? AccountLinesResponse
: T extends AccountNFTsRequest
@@ -280,11 +314,13 @@ export type RequestResponseMap<T> = T extends AccountChannelsRequest
: T extends AccountOffersRequest
? AccountOffersResponse
: T extends AccountTxRequest
? AccountTxResponse
? AccountTxVersionResponseMap<Version>
: T extends AMMInfoRequest
? AMMInfoResponse
: T extends GatewayBalancesRequest
? GatewayBalancesResponse
: T extends GetAggregatePriceRequest
? GetAggregatePriceResponse
: T extends NoRippleCheckRequest
? NoRippleCheckResponse
: // NOTE: The order of these LedgerRequest types is important
@@ -344,15 +380,15 @@ export type RequestResponseMap<T> = T extends AccountChannelsRequest
// then we'd get the wrong response type, LedgerResponse, instead of
// LedgerResponseExpanded.
T extends LedgerRequestExpandedTransactionsBinary
? LedgerResponse
? LedgerVersionResponseMap<Version>
: T extends LedgerRequestExpandedAccountsAndTransactions
? LedgerResponseExpanded
? LedgerResponseExpanded<Version>
: T extends LedgerRequestExpandedTransactionsOnly
? LedgerResponseExpanded
? LedgerResponseExpanded<Version>
: T extends LedgerRequestExpandedAccountsOnly
? LedgerResponseExpanded
? LedgerResponseExpanded<Version>
: T extends LedgerRequest
? LedgerResponse
? LedgerVersionResponseMap<Version>
: T extends LedgerClosedRequest
? LedgerClosedResponse
: T extends LedgerCurrentRequest
@@ -364,11 +400,11 @@ export type RequestResponseMap<T> = T extends AccountChannelsRequest
: T extends SubmitRequest
? SubmitResponse
: T extends SubmitMultisignedRequest
? SubmitMultisignedResponse
? SubmitMultisignedVersionResponseMap<Version>
: T extends TransactionEntryRequest
? TransactionEntryResponse
: T extends TxRequest
? TxResponse
? TxVersionResponseMap<Version>
: T extends BookOffersRequest
? BookOffersResponse
: T extends DepositAuthorizedRequest
@@ -393,6 +429,10 @@ export type RequestResponseMap<T> = T extends AccountChannelsRequest
? ServerStateResponse
: T extends ServerDefinitionsRequest
? ServerDefinitionsResponse
: T extends FeatureAllRequest
? FeatureAllResponse
: T extends FeatureOneRequest
? FeatureOneResponse
: T extends PingRequest
? PingResponse
: T extends RandomRequest
@@ -403,22 +443,29 @@ export type RequestResponseMap<T> = T extends AccountChannelsRequest
? NFTSellOffersResponse
: T extends NFTInfoRequest
? NFTInfoResponse
: T extends NFTsByIssuerRequest
? NFTsByIssuerResponse
: T extends NFTHistoryRequest
? NFTHistoryResponse
: Response
: Response<Version>
export type MarkerRequest = Request & {
limit?: number
marker?: unknown
}
export type MarkerResponse = Response & {
export type MarkerResponse<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = Response<Version> & {
result: {
marker?: unknown
}
}
export type RequestAllResponseMap<T> = T extends AccountChannelsRequest
export type RequestAllResponseMap<
T,
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = T extends AccountChannelsRequest
? AccountChannelsResponse
: T extends AccountLinesRequest
? AccountLinesResponse
@@ -427,14 +474,12 @@ export type RequestAllResponseMap<T> = T extends AccountChannelsRequest
: T extends AccountOffersRequest
? AccountOffersResponse
: T extends AccountTxRequest
? AccountTxResponse
? AccountTxVersionResponseMap<Version>
: T extends LedgerDataRequest
? LedgerDataResponse
: T extends AccountTxRequest
? AccountTxResponse
: T extends BookOffersRequest
? BookOffersResponse
: MarkerResponse
: MarkerResponse<Version>
export {
// Allow users to define their own requests and responses. This is useful for releasing experimental versions
@@ -452,6 +497,7 @@ export {
AccountInfoAccountFlags,
AccountInfoRequest,
AccountInfoResponse,
AccountInfoV1Response,
AccountQueueData,
AccountQueueTransaction,
AccountLinesRequest,
@@ -469,15 +515,19 @@ export {
AccountOffersResponse,
AccountTxRequest,
AccountTxResponse,
AccountTxV1Response,
AccountTxTransaction,
GatewayBalance,
GatewayBalancesRequest,
GatewayBalancesResponse,
GetAggregatePriceRequest,
GetAggregatePriceResponse,
NoRippleCheckRequest,
NoRippleCheckResponse,
// ledger methods
LedgerRequest,
LedgerResponse,
LedgerV1Response,
LedgerQueueData,
LedgerBinary,
LedgerModifiedOfferCreateTransaction,
@@ -497,10 +547,12 @@ export {
SubmitResponse,
SubmitMultisignedRequest,
SubmitMultisignedResponse,
SubmitMultisignedV1Response,
TransactionEntryRequest,
TransactionEntryResponse,
TxRequest,
TxResponse,
TxV1Response,
// path and order book methods with types
BookOffersRequest,
BookOffer,
@@ -553,6 +605,8 @@ export {
ServerState,
StateAccountingFinal,
StateAccounting,
FeatureRequest,
FeatureResponse,
// utility methods
PingRequest,
PingResponse,
@@ -570,6 +624,8 @@ export {
NFTHistoryRequest,
NFTHistoryResponse,
NFTHistoryTransaction,
NFTsByIssuerRequest,
NFTsByIssuerResponse,
// AMM methods
AMMInfoRequest,
AMMInfoResponse,

View File

@@ -1,4 +1,5 @@
import { Ledger } from '../ledger'
import { APIVersion, DEFAULT_API_VERSION, RIPPLED_API_V1 } from '../common'
import { Ledger, LedgerV1, LedgerVersionMap } from '../ledger/Ledger'
import { LedgerEntryFilter } from '../ledger/LedgerEntry'
import { Transaction, TransactionAndMetadata } from '../transactions'
import { TransactionMetadata } from '../transactions/metadata'
@@ -207,6 +208,12 @@ export interface LedgerBinary
transactions?: string[]
}
export interface LedgerBinaryV1
extends Omit<Omit<LedgerV1, 'transactions'>, 'accountState'> {
accountState?: string[]
transactions?: string[]
}
interface LedgerResponseBase {
/** Unique identifying hash of the entire ledger. */
ledger_hash: string
@@ -231,6 +238,11 @@ interface LedgerResponseResult extends LedgerResponseBase {
ledger: LedgerBinary
}
interface LedgerV1ResponseResult extends LedgerResponseBase {
/** The complete header data of this {@link Ledger}. */
ledger: LedgerBinaryV1
}
/**
* Response expected from a {@link LedgerRequest}.
* This is the default request response, triggered when `expand` and `binary` are both false.
@@ -241,9 +253,31 @@ export interface LedgerResponse extends BaseResponse {
result: LedgerResponseResult
}
interface LedgerResponseExpandedResult extends LedgerResponseBase {
/**
* Response expected from a {@link LedgerRequest}.
* This is the default request response, triggered when `expand` and `binary` are both false.
* This is the response for API version 1.
*
* @category ResponsesV1
*/
export interface LedgerV1Response extends BaseResponse {
result: LedgerV1ResponseResult
}
/**
* Type to map between the API version and the response type.
*
* @category Responses
*/
export type LedgerVersionResponseMap<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = Version extends typeof RIPPLED_API_V1 ? LedgerV1Response : LedgerResponse
interface LedgerResponseExpandedResult<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> extends LedgerResponseBase {
/** The complete header data of this {@link Ledger}. */
ledger: Ledger
ledger: LedgerVersionMap<Version>
}
/**
@@ -254,6 +288,8 @@ interface LedgerResponseExpandedResult extends LedgerResponseBase {
*
* @category Responses
*/
export interface LedgerResponseExpanded extends BaseResponse {
result: LedgerResponseExpandedResult
export interface LedgerResponseExpanded<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> extends BaseResponse {
result: LedgerResponseExpandedResult<Version>
}

View File

@@ -0,0 +1,68 @@
import { NFToken } from '../common'
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
/**
* The nfts_by_issuer method returns a list of NFTokens issued by the account.
* The order of the NFTs is not associated with the date the NFTs were minted.
* Expects a response in the form of a {@link
* NFTsByIssuerResponse}.
*
* @category Requests
*/
export interface NFTsByIssuerRequest
extends BaseRequest,
LookupByLedgerRequest {
command: 'nfts_by_issuer'
/**
* A unique identifier for the account, most commonly the account's address
*/
issuer: string
/**
* Value from a previous paginated response. Resume retrieving data where
* that response left off. This value is stable even if there is a change in
* the server's range of available ledgers.
*/
marker?: unknown
/**
* Filter NFTs issued by this issuer that have this taxon.
*/
nft_taxon?: number
/**
* Default varies. Limit the number of transactions to retrieve. The server
* is not required to honor this value.
*/
limit?: number
}
/**
* Expected response from an {@link NFTsByIssuerRequest}.
*
* @category Responses
*/
export interface NFTsByIssuerResponse extends BaseResponse {
result: {
/**
* The unique identifier for the account, most commonly the account's address
*/
issuer: string
/**
* A list of NFTs issued by the account.
* The order of the NFTs is not associated with the date the NFTs were minted.
*/
nfts: NFToken[]
/**
* Server-defined value indicating the response is paginated. Pass this
* to the next call to resume where this call left off.
*/
marker?: unknown
/**
* The limit value used in the request.
*/
limit?: number
/**
* Use to filter NFTs issued by this issuer that have this taxon.
*/
nft_taxon?: number
}
}

View File

@@ -1,3 +1,4 @@
import { APIVersion, DEFAULT_API_VERSION, RIPPLED_API_V1 } from '../common'
import { Transaction } from '../transactions'
import { BaseRequest, BaseResponse } from './baseMethod'
@@ -24,28 +25,59 @@ export interface SubmitMultisignedRequest extends BaseRequest {
fail_hard?: boolean
}
/**
* Common properties for multisigned transaction responses.
*
* @category Responses
*/
interface BaseSubmitMultisignedResult {
/**
* Code indicating the preliminary result of the transaction, for example.
* `tesSUCCESS`.
*/
engine_result: string
/**
* Numeric code indicating the preliminary result of the transaction,
* directly correlated to `engine_result`.
*/
engine_result_code: number
/** Human-readable explanation of the preliminary transaction result. */
engine_result_message: string
/** The complete transaction in hex string format. */
tx_blob: string
/** The complete transaction in JSON format. */
tx_json: Transaction
}
/**
* Response expected from a {@link SubmitMultisignedRequest}.
*
* @category Responses
*/
export interface SubmitMultisignedResponse extends BaseResponse {
result: {
/**
* Code indicating the preliminary result of the transaction, for example.
* `tesSUCCESS` .
*/
engine_result: string
/**
* Numeric code indicating the preliminary result of the transaction,
* directly correlated to `engine_result`.
*/
engine_result_code: number
/** Human-readable explanation of the preliminary transaction result. */
engine_result_message: string
/** The complete transaction in hex string format. */
tx_blob: string
/** The complete transaction in JSON format. */
result: BaseSubmitMultisignedResult & {
hash?: string
}
}
/**
* Response expected from a {@link SubmitMultisignedRequest} using api_version 1.
*
* @category ResponsesV1
*/
export interface SubmitMultisignedV1Response extends BaseResponse {
result: BaseSubmitMultisignedResult & {
tx_json: Transaction & { hash?: string }
}
}
/**
* Type to map between the API version and the response type.
*
* @category Responses
*/
export type SubmitMultisignedVersionResponseMap<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = Version extends typeof RIPPLED_API_V1
? SubmitMultisignedV1Response
: SubmitMultisignedResponse

View File

@@ -1,3 +1,9 @@
import {
APIVersion,
DEFAULT_API_VERSION,
RIPPLED_API_V1,
RIPPLED_API_V2,
} from '../common'
import { Transaction, TransactionMetadata } from '../transactions'
import { BaseTransaction } from '../transactions/common'
@@ -41,6 +47,47 @@ export interface TxRequest extends BaseRequest {
max_ledger?: number
}
/**
* Common properties of transaction responses.
*
* @category Responses
*/
interface BaseTxResult<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
T extends BaseTransaction = Transaction,
> {
/** The SHA-512 hash of the transaction. */
hash: string
/**
* The Concise Transaction Identifier of the transaction (16-byte hex string)
*/
ctid?: string
/** The ledger index of the ledger that includes this transaction. */
ledger_index?: number
/** Unique hashed string Transaction metadata blob, which describes the results of the transaction.
* Can be undefined if a transaction has not been validated yet. This field is omitted if binary
* binary format is not requested. */
meta_blob?: Version extends typeof RIPPLED_API_V2
? TransactionMetadata<T> | string
: never
/** Transaction metadata, which describes the results of the transaction.
* Can be undefined if a transaction has not been validated yet. */
meta?: TransactionMetadata<T> | string
/**
* If true, this data comes from a validated ledger version; if omitted or.
* Set to false, this data is not final.
*/
validated?: boolean
/**
* The time the transaction was closed, in seconds since the Ripple Epoch.
*/
close_time_iso?: string
/**
* This number measures the number of seconds since the "Ripple Epoch" of January 1, 2000 (00:00 UTC)
*/
date?: number
}
/**
* Response expected from a {@link TxRequest}.
*
@@ -48,28 +95,7 @@ export interface TxRequest extends BaseRequest {
*/
export interface TxResponse<T extends BaseTransaction = Transaction>
extends BaseResponse {
result: {
/** The SHA-512 hash of the transaction. */
hash: string
/**
* The Concise Transaction Identifier of the transaction (16-byte hex string)
*/
ctid?: string
/** The ledger index of the ledger that includes this transaction. */
ledger_index?: number
/** Transaction metadata, which describes the results of the transaction.
* Can be undefined if a transaction has not been validated yet. */
meta?: TransactionMetadata<T> | string
/**
* If true, this data comes from a validated ledger version; if omitted or.
* Set to false, this data is not final.
*/
validated?: boolean
/**
* This number measures the number of seconds since the "Ripple Epoch" of January 1, 2000 (00:00 UTC)
*/
date?: number
} & T
result: BaseTxResult<typeof RIPPLED_API_V2, T> & { tx_json: T }
/**
* If true, the server was able to search all of the specified ledger
* versions, and the transaction was in none of them. If false, the server did
@@ -78,3 +104,29 @@ export interface TxResponse<T extends BaseTransaction = Transaction>
*/
searched_all?: boolean
}
/**
* Response expected from a {@link TxRequest} using API version 1.
*
* @category ResponsesV1
*/
export interface TxV1Response<T extends BaseTransaction = Transaction>
extends BaseResponse {
result: BaseTxResult<typeof RIPPLED_API_V1, T> & T
/**
* If true, the server was able to search all of the specified ledger
* versions, and the transaction was in none of them. If false, the server did
* not have all of the specified ledger versions available, so it is not sure.
* If one of them might contain the transaction.
*/
searched_all?: boolean
}
/**
* Type to map between the API version and the response type.
*
* @category Responses
*/
export type TxVersionResponseMap<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = Version extends typeof RIPPLED_API_V1 ? TxV1Response : TxResponse

View File

@@ -21,6 +21,7 @@ export enum AMMDepositFlags {
tfTwoAsset = 0x00100000,
tfOneAssetLPToken = 0x00200000,
tfLimitLPToken = 0x00400000,
tfTwoAssetIfEmpty = 0x00800000,
}
export interface AMMDepositFlagsInterface extends GlobalFlags {
@@ -29,6 +30,7 @@ export interface AMMDepositFlagsInterface extends GlobalFlags {
tfTwoAsset?: boolean
tfOneAssetLPToken?: boolean
tfLimitLPToken?: boolean
tfTwoAssetIfEmpty?: boolean
}
/**

View File

@@ -58,6 +58,8 @@ export {
OfferCreateFlagsInterface,
OfferCreate,
} from './offerCreate'
export { OracleDelete } from './oracleDelete'
export { OracleSet } from './oracleSet'
export { PaymentFlags, PaymentFlagsInterface, Payment } from './payment'
export {
PaymentChannelClaimFlags,

View File

@@ -40,6 +40,7 @@ export interface DeletedNode {
DeletedNode: {
LedgerEntryType: string
LedgerIndex: string
PreviousFields?: { [field: string]: unknown }
FinalFields: { [field: string]: unknown }
}
}

View File

@@ -0,0 +1,32 @@
import {
BaseTransaction,
isNumber,
validateBaseTransaction,
validateRequiredField,
} from './common'
/**
* Delete an Oracle ledger entry.
*
* @category Transaction Models
*/
export interface OracleDelete extends BaseTransaction {
TransactionType: 'OracleDelete'
/**
* A unique identifier of the price oracle for the Account.
*/
OracleDocumentID: number
}
/**
* Verify the form and type of a OracleDelete at runtime.
*
* @param tx - A OracleDelete Transaction.
* @throws When the OracleDelete is malformed.
*/
export function validateOracleDelete(tx: Record<string, unknown>): void {
validateBaseTransaction(tx)
validateRequiredField(tx, 'OracleDocumentID', isNumber)
}

View File

@@ -0,0 +1,176 @@
import { ValidationError } from '../../errors'
import { PriceData } from '../common'
import {
BaseTransaction,
isNumber,
isString,
validateBaseTransaction,
validateOptionalField,
validateRequiredField,
} from './common'
const PRICE_DATA_SERIES_MAX_LENGTH = 10
const SCALE_MAX = 10
/**
* Creates a new Oracle ledger entry or updates the fields of an existing one, using the Oracle ID.
*
* The oracle provider must complete these steps before submitting this transaction:
* 1. Create or own the XRPL account in the Owner field and have enough XRP to meet the reserve and transaction fee requirements.
* 2. Publish the XRPL account public key, so it can be used for verification by dApps.
* 3. Publish a registry of available price oracles with their unique OracleDocumentID.
*
* @category Transaction Models
*/
export interface OracleSet extends BaseTransaction {
TransactionType: 'OracleSet'
/**
* A unique identifier of the price oracle for the Account.
*/
OracleDocumentID: number
/**
* The time the data was last updated, represented as a unix timestamp in seconds.
*/
LastUpdateTime: number
/**
* An array of up to 10 PriceData objects, each representing the price information
* for a token pair. More than five PriceData objects require two owner reserves.
*/
PriceDataSeries: PriceData[]
/**
* An arbitrary value that identifies an oracle provider, such as Chainlink, Band,
* or DIA. This field is a string, up to 256 ASCII hex encoded characters (0x20-0x7E).
* This field is required when creating a new Oracle ledger entry, but is optional for updates.
*/
Provider?: string
/**
* An optional Universal Resource Identifier to reference price data off-chain. This field is limited to 256 bytes.
*/
URI?: string
/**
* Describes the type of asset, such as "currency", "commodity", or "index". This field is a string, up to 16 ASCII
* hex encoded characters (0x20-0x7E). This field is required when creating a new Oracle ledger entry, but is optional
* for updates.
*/
AssetClass?: string
}
/**
* Verify the form and type of a OracleSet at runtime.
*
* @param tx - A OracleSet Transaction.
* @throws When the OracleSet is malformed.
*/
// eslint-disable-next-line max-lines-per-function -- necessary to validate many fields
export function validateOracleSet(tx: Record<string, unknown>): void {
validateBaseTransaction(tx)
validateRequiredField(tx, 'OracleDocumentID', isNumber)
validateRequiredField(tx, 'LastUpdateTime', isNumber)
validateOptionalField(tx, 'Provider', isString)
validateOptionalField(tx, 'URI', isString)
validateOptionalField(tx, 'AssetClass', isString)
// eslint-disable-next-line max-lines-per-function -- necessary to validate many fields
validateRequiredField(tx, 'PriceDataSeries', (value) => {
if (!Array.isArray(value)) {
throw new ValidationError('OracleSet: PriceDataSeries must be an array')
}
if (value.length > PRICE_DATA_SERIES_MAX_LENGTH) {
throw new ValidationError(
`OracleSet: PriceDataSeries must have at most ${PRICE_DATA_SERIES_MAX_LENGTH} PriceData objects`,
)
}
// TODO: add support for handling inner objects easier (similar to validateRequiredField/validateOptionalField)
for (const priceData of value) {
if (typeof priceData !== 'object') {
throw new ValidationError(
'OracleSet: PriceDataSeries must be an array of objects',
)
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
if (priceData.PriceData == null) {
throw new ValidationError(
'OracleSet: PriceDataSeries must have a `PriceData` object',
)
}
// check if priceData only has PriceData
if (Object.keys(priceData).length !== 1) {
throw new ValidationError(
'OracleSet: PriceDataSeries must only have a single PriceData object',
)
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
if (typeof priceData.PriceData.BaseAsset !== 'string') {
throw new ValidationError(
'OracleSet: PriceDataSeries must have a `BaseAsset` string',
)
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
if (typeof priceData.PriceData.QuoteAsset !== 'string') {
throw new ValidationError(
'OracleSet: PriceDataSeries must have a `QuoteAsset` string',
)
}
// Either AssetPrice and Scale are both present or both excluded
if (
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
(priceData.PriceData.AssetPrice == null) !==
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
(priceData.PriceData.Scale == null)
) {
throw new ValidationError(
'OracleSet: PriceDataSeries must have both `AssetPrice` and `Scale` if any are present',
)
}
if (
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
'AssetPrice' in priceData.PriceData &&
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
!isNumber(priceData.PriceData.AssetPrice)
) {
throw new ValidationError('OracleSet: invalid field AssetPrice')
}
if (
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
'Scale' in priceData.PriceData &&
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
!isNumber(priceData.PriceData.Scale)
) {
throw new ValidationError('OracleSet: invalid field Scale')
}
if (
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
priceData.PriceData.Scale < 0 ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
priceData.PriceData.Scale > SCALE_MAX
) {
throw new ValidationError(
`OracleSet: Scale must be in range 0-${SCALE_MAX}`,
)
}
}
return true
})
}

View File

@@ -26,7 +26,7 @@ export enum PaymentFlags {
* This is intended to force the transaction to take arbitrage opportunities.
* Most clients do not need this.
*/
tfNoDirectRipple = 0x00010000,
tfNoRippleDirect = 0x00010000,
/**
* If the specified Amount cannot be sent without spending more than SendMax,
* reduce the received amount instead of failing outright. See Partial.
@@ -88,7 +88,7 @@ export interface PaymentFlagsInterface extends GlobalFlags {
* This is intended to force the transaction to take arbitrage opportunities.
* Most clients do not need this.
*/
tfNoDirectRipple?: boolean
tfNoRippleDirect?: boolean
/**
* If the specified Amount cannot be sent without spending more than SendMax,
* reduce the received amount instead of failing outright. See Partial.

View File

@@ -43,6 +43,8 @@ import {
import { NFTokenMint, validateNFTokenMint } from './NFTokenMint'
import { OfferCancel, validateOfferCancel } from './offerCancel'
import { OfferCreate, validateOfferCreate } from './offerCreate'
import { OracleDelete, validateOracleDelete } from './oracleDelete'
import { OracleSet, validateOracleSet } from './oracleSet'
import { Payment, validatePayment } from './payment'
import {
PaymentChannelClaim,
@@ -120,6 +122,8 @@ export type SubmittableTransaction =
| NFTokenMint
| OfferCancel
| OfferCreate
| OracleDelete
| OracleSet
| Payment
| PaymentChannelClaim
| PaymentChannelCreate
@@ -330,6 +334,14 @@ export function validate(transaction: Record<string, unknown>): void {
validateOfferCreate(tx)
break
case 'OracleDelete':
validateOracleDelete(tx)
break
case 'OracleSet':
validateOracleSet(tx)
break
case 'Payment':
validatePayment(tx)
break

View File

@@ -1,7 +1,7 @@
import BigNumber from 'bignumber.js'
import { xAddressToClassicAddress, isValidXAddress } from 'ripple-address-codec'
import type { Client } from '..'
import { type Client } from '..'
import { ValidationError, XrplError } from '../errors'
import { AccountInfoRequest, AccountObjectsRequest } from '../models/methods'
import { Transaction } from '../models/transactions'
@@ -17,7 +17,6 @@ const LEDGER_OFFSET = 20
// Mainnet and testnet are exceptions. More context: https://github.com/XRPLF/rippled/pull/4370
const RESTRICTED_NETWORKS = 1024
const REQUIRED_NETWORKID_VERSION = '1.11.0'
const HOOKS_TESTNET_ID = 21338
/**
* Determines whether the source rippled version is not later than the target rippled version.
@@ -87,8 +86,7 @@ function isNotLaterRippledVersion(source: string, target: string): boolean {
/**
* Determine if the transaction required a networkID to be valid.
* Transaction needs networkID if later than restricted ID and either the network is hooks testnet
* or build version is >= 1.11.0
* Transaction needs networkID if later than restricted ID and build version is >= 1.11.0
*
* @param client -- The connected client.
* @returns True if required networkID, false otherwise.
@@ -99,12 +97,8 @@ export function txNeedsNetworkID(client: Client): boolean {
client.networkID > RESTRICTED_NETWORKS
) {
if (
(client.buildVersion &&
isNotLaterRippledVersion(
REQUIRED_NETWORKID_VERSION,
client.buildVersion,
)) ||
client.networkID === HOOKS_TESTNET_ID
client.buildVersion &&
isNotLaterRippledVersion(REQUIRED_NETWORKID_VERSION, client.buildVersion)
) {
return true
}

View File

@@ -1,6 +1,6 @@
import BigNumber from 'bignumber.js'
import type { Client } from '..'
import { type Client } from '..'
import { XrplError } from '../errors'
const NUM_DECIMAL_PLACES = 6
@@ -20,8 +20,11 @@ export default async function getFeeXrp(
): Promise<string> {
const feeCushion = cushion ?? client.feeCushion
const serverInfo = (await client.request({ command: 'server_info' })).result
.info
const serverInfo = (
await client.request({
command: 'server_info',
})
).result.info
const baseFee = serverInfo.validated_ledger?.base_fee_xrp

View File

@@ -10,7 +10,7 @@ import type {
} from '..'
import { ValidationError, XrplError } from '../errors'
import { Signer } from '../models/common'
import { TxRequest, TxResponse } from '../models/methods'
import { TxResponse } from '../models/methods'
import { BaseTransaction } from '../models/transactions/common'
/** Approximate time for a ledger to close, in milliseconds */
@@ -129,7 +129,7 @@ export async function waitForFinalTransactionOutcome<
}
const txResponse = await client
.request<TxRequest, TxResponse<T>>({
.request({
command: 'tx',
transaction: txHash,
})
@@ -153,7 +153,9 @@ export async function waitForFinalTransactionOutcome<
})
if (txResponse.result.validated) {
return txResponse
// TODO: resolve the type assertion below
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- we know that txResponse is of type TxResponse
return txResponse as TxResponse<T>
}
return waitForFinalTransactionOutcome<T>(

View File

@@ -8,8 +8,9 @@ import BigNumber from 'bignumber.js'
import { decode, encode } from 'ripple-binary-codec'
import { ValidationError, XrplError } from '../../errors'
import type { Ledger } from '../../models/ledger'
import { APIVersion } from '../../models'
import { LedgerEntry } from '../../models/ledger'
import { LedgerVersionMap } from '../../models/ledger/Ledger'
import { Transaction, TransactionMetadata } from '../../models/transactions'
import HashPrefix from './HashPrefix'
@@ -99,7 +100,9 @@ export function hashSignedTx(tx: Transaction | string): string {
* @returns The hash of the ledger.
* @category Utilities
*/
export function hashLedgerHeader(ledgerHeader: Ledger): string {
export function hashLedgerHeader(
ledgerHeader: LedgerVersionMap<APIVersion>,
): string {
const prefix = HashPrefix.LEDGER.toString(HEX).toUpperCase()
const ledger =
@@ -158,7 +161,7 @@ export function hashStateTree(entries: LedgerEntry[]): string {
}
function computeTransactionHash(
ledger: Ledger,
ledger: LedgerVersionMap<APIVersion>,
options: HashLedgerHeaderOptions,
): string {
const { transaction_hash } = ledger
@@ -188,7 +191,7 @@ function computeTransactionHash(
}
function computeStateHash(
ledger: Ledger,
ledger: LedgerVersionMap<APIVersion>,
options: HashLedgerHeaderOptions,
): string {
const { account_hash } = ledger
@@ -222,7 +225,7 @@ function computeStateHash(
* @category Utilities
*/
function hashLedger(
ledger: Ledger,
ledger: LedgerVersionMap<APIVersion>,
options: {
computeTreeHashes?: boolean
} = {},

View File

@@ -23,6 +23,7 @@ import {
} from 'ripple-binary-codec'
import { verify as verifyKeypairSignature } from 'ripple-keypairs'
import type { APIVersion } from '../models'
import { LedgerEntry } from '../models/ledger'
import { Response } from '../models/methods'
import { PaymentChannelClaim } from '../models/transactions/paymentChannelClaim'
@@ -157,7 +158,7 @@ function isValidAddress(address: string): boolean {
* @returns Whether the response has more pages of data.
* @category Utilities
*/
function hasNextPage(response: Response): boolean {
function hasNextPage(response: Response<APIVersion>): boolean {
// eslint-disable-next-line @typescript-eslint/dot-notation -- only checking if it exists
return Boolean(response.result['marker'])
}

View File

@@ -7,6 +7,7 @@ import {
Payment,
Transaction,
} from '../../src'
import { ValidationError } from '../../src/errors'
import rippled from '../fixtures/rippled'
import {
setupClient,
@@ -19,10 +20,11 @@ const NetworkID = 1025
const Fee = '10'
const Sequence = 1432
const LastLedgerSequence = 2908734
const HOOKS_TESTNET_ID = 21338
describe('client.autofill', function () {
let testContext: XrplTestContext
const AMOUNT = '1234'
let paymentTx: Payment
async function setupMockRippledVersionAndID(
buildVersion: string,
@@ -41,10 +43,68 @@ describe('client.autofill', function () {
await testContext.client.connect()
}
beforeEach(async () => {
beforeAll(async () => {
testContext = await setupClient()
})
afterEach(async () => teardownClient(testContext))
afterAll(async () => teardownClient(testContext))
beforeEach(async () => {
paymentTx = {
TransactionType: 'Payment',
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
Amount: AMOUNT,
Destination: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy',
DestinationTag: 1,
Fee: '12',
Flags: 2147483648,
LastLedgerSequence: 65953073,
Sequence: 65923914,
SigningPubKey:
'02F9E33F16DF9507705EC954E3F94EB5F10D1FC4A354606DBE6297DBB1096FE654',
TxnSignature:
'3045022100E3FAE0EDEC3D6A8FF6D81BC9CF8288A61B7EEDE8071E90FF9314CB4621058D10022043545CF631706D700CEE65A1DB83EFDD185413808292D9D90F14D87D3DC2D8CB',
InvoiceID:
'6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B',
Paths: [
[{ currency: 'BTC', issuer: 'r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X' }],
],
SendMax: '100000000',
}
})
it('Validate Payment transaction API v2: Payment Transaction: Specify Only Amount field', async function () {
const txResult = await testContext.client.autofill(paymentTx)
assert.strictEqual(txResult.Amount, AMOUNT)
})
it('Validate Payment transaction API v2: Payment Transaction: Specify Only DeliverMax field', async function () {
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
paymentTx.DeliverMax = paymentTx.Amount
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
delete paymentTx.Amount
const txResult = await testContext.client.autofill(paymentTx)
assert.strictEqual(txResult.Amount, AMOUNT)
})
it('Validate Payment transaction API v2: Payment Transaction: identical DeliverMax and Amount fields', async function () {
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
paymentTx.DeliverMax = paymentTx.Amount
const txResult = await testContext.client.autofill(paymentTx)
assert.strictEqual(txResult.Amount, AMOUNT)
assert.strictEqual('DeliverMax' in txResult, false)
})
it('Validate Payment transaction API v2: Payment Transaction: differing DeliverMax and Amount fields', async function () {
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
paymentTx.DeliverMax = '6789'
paymentTx.Amount = '1234'
await assertRejects(testContext.client.autofill(paymentTx), ValidationError)
})
it('should not autofill if fields are present', async function () {
const tx: Transaction = {
@@ -141,26 +201,6 @@ describe('client.autofill', function () {
assert.strictEqual(txResult.NetworkID, undefined)
})
// Hooks Testnet requires networkID in transaction regardless of version.
// More context: https://github.com/XRPLF/rippled/pull/4370
it('overrides network ID for hooks testnet', async function () {
await setupMockRippledVersionAndID('1.10.1', HOOKS_TESTNET_ID)
const tx: Payment = {
TransactionType: 'Payment',
Account: 'XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8yuPT7y4xaEHi',
Amount: '1234',
Destination: 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
Fee,
Sequence,
LastLedgerSequence,
}
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
const txResult = await testContext.client.autofill(tx)
assert.strictEqual(txResult.NetworkID, HOOKS_TESTNET_ID)
})
it('converts Account & Destination X-address to their classic address', async function () {
const tx: Payment = {
TransactionType: 'Payment',

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any -- required for formatting transactions */
import { expect } from 'chai'
import cloneDeep from 'lodash/cloneDeep'
@@ -24,7 +23,7 @@ describe('client handling of tfPartialPayments', function () {
testContext.mockRippled!.addResponse('tx', rippled.tx.Payment)
const resp = await testContext.client.request({
command: 'tx',
transaction: rippled.tx.Payment.result.hash,
transaction: rippled.tx.Payment.result.tx_json.hash,
})
expect(resp.warnings).to.equal(undefined)
@@ -35,7 +34,7 @@ describe('client handling of tfPartialPayments', function () {
testContext.mockRippled!.addResponse('tx', mockResponse)
const resp = await testContext.client.request({
command: 'tx',
transaction: mockResponse.result.hash,
transaction: mockResponse.result.tx_json.hash,
})
expect(resp.warnings).to.deep.equal([
@@ -51,7 +50,7 @@ describe('client handling of tfPartialPayments', function () {
testContext.mockRippled!.addResponse('tx', mockResponse)
const resp = await testContext.client.request({
command: 'tx',
transaction: mockResponse.result.hash,
transaction: mockResponse.result.tx_json.hash,
})
expect(resp.warnings).to.deep.equal([
@@ -82,8 +81,10 @@ describe('client handling of tfPartialPayments', function () {
}
const mockResponse = rippled.account_tx.normal
mockResponse.result.transactions.push({
tx: partial.result,
tx_json: partial.result.tx_json,
meta: partial.result.meta,
validated: true,
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- we are mocking the response
} as any)
testContext.mockRippled!.addResponse('account_tx', mockResponse)
@@ -105,8 +106,10 @@ describe('client handling of tfPartialPayments', function () {
const partial = { ...rippled.tx.Payment, result: partialPaymentXRP }
const mockResponse = rippled.account_tx.normal
mockResponse.result.transactions.push({
tx: partial.result,
tx_json: partial.result.tx_json,
meta: partial.result.meta,
validated: true,
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- we are mocking the response
} as any)
testContext.mockRippled!.addResponse('account_tx', mockResponse)
@@ -138,7 +141,7 @@ describe('client handling of tfPartialPayments', function () {
it('transaction_entry with XRP tfPartialPayment', async function () {
const mockResponse = cloneDeep(rippled.transaction_entry)
mockResponse.result.tx_json.Amount = '1000'
mockResponse.result.tx_json.DeliverMax = '1000'
testContext.mockRippled!.addResponse('transaction_entry', mockResponse)
const resp = await testContext.client.request({
command: 'transaction_entry',

View File

@@ -10,9 +10,18 @@ import {
const rippledResponse = function (request: Request): Record<string, unknown> {
if ('marker' in request) {
return rippled.ledger_data.last_page
return rippled.ledger_data.lastPage
}
return rippled.ledger_data.first_page
return rippled.ledger_data.firstPage
}
const rippledResponseFirstEmpty = function (
request: Request,
): Record<string, unknown> {
if ('marker' in request) {
return rippled.ledger_data.lastPage
}
return rippled.ledger_data.firstPageEmpty
}
describe('client.requestAll', function () {
@@ -34,14 +43,25 @@ describe('client.requestAll', function () {
)
})
it('rejects when there are no more pages', async function () {
it('stops when there are no more pages', async function () {
testContext.mockRippled!.addResponse(
'ledger_data',
rippled.ledger_data.last_page,
rippled.ledger_data.lastPage,
)
const allResponses = await testContext.client.requestAll({
command: 'ledger_data',
})
assert.equal(allResponses.length, 1)
})
it('handles when the first page has no results', async function () {
testContext.mockRippled!.addResponse(
'ledger_data',
rippledResponseFirstEmpty,
)
const allResponses = await testContext.client.requestAll({
command: 'ledger_data',
})
assert.equal(allResponses.length, 2)
})
})

View File

@@ -11,9 +11,9 @@ import { assertRejects } from '../testUtils'
const rippledResponse = function (request: Request): Record<string, unknown> {
if ('marker' in request) {
return rippled.ledger_data.last_page
return rippled.ledger_data.lastPage
}
return rippled.ledger_data.first_page
return rippled.ledger_data.firstPage
}
describe('client.requestNextPage', function () {

View File

@@ -91,7 +91,7 @@
"TransactionIndex": 12,
"TransactionResult": "tesSUCCESS"
},
"tx": {
"tx_json": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Destination": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"DestinationTag": 13,
@@ -169,7 +169,7 @@
"TransactionIndex": 59,
"TransactionResult": "tesSUCCESS"
},
"tx": {
"tx_json": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Authorize": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "10",

View File

@@ -6,8 +6,9 @@ import fabric from './bookOffers'
import usd_xrp from './bookOffersUsdXrp.json'
import xrp_usd from './bookOffersXrpUsd.json'
import normalLedger from './ledger.json'
import first_page from './ledgerDataFirstPage.json'
import last_page from './ledgerDataLastPage.json'
import firstPage from './ledgerDataFirstPage.json'
import firstPageEmpty from './ledgerDataFirstPageEmpty.json'
import lastPage from './ledgerDataLastPage.json'
import iouPartialPayment from './partialPaymentIOU.json'
import xrpPartialPayment from './partialPaymentXRP.json'
import normalServerInfo from './serverInfo.json'
@@ -82,8 +83,9 @@ const book_offers = {
}
const ledger_data = {
first_page,
last_page,
firstPage,
firstPageEmpty,
lastPage,
}
const server_info = {

View File

@@ -0,0 +1,14 @@
{
"id": 0,
"status": "success",
"type": "response",
"result": {
"ledger_hash":
"102A6E70FFB18C18E97BB56E3047B0E45EA1BCC90BFCCB8CBB0D07BF0E2AB449",
"ledger_index": 38202000,
"marker":
"000B714B790C3C79FEE00D17C4DEB436B375466F29679447BA64F265FD63D730",
"state": [],
"validated": true
}
}

View File

@@ -1,18 +1,20 @@
{
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Amount": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "10"
"tx_json": {
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"DeliverMax": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "10"
},
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"Fee": "10000",
"Flags": 131072,
"Sequence": 23295,
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
"TransactionType": "Payment",
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A"
},
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"Fee": "10000",
"Flags": 131072,
"Sequence": 23295,
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
"TransactionType": "Payment",
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
"meta": {
"AffectedNodes": [
{

View File

@@ -1,14 +1,16 @@
{
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Amount": "2000000",
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"Fee": "10000",
"Flags": 131072,
"Sequence": 23295,
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
"TransactionType": "Payment",
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
"tx_json": {
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"DeliverMax": "2000000",
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"Fee": "10000",
"Flags": 131072,
"Sequence": 23295,
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
"TransactionType": "Payment",
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A"
},
"meta": {
"AffectedNodes": [
{

View File

@@ -50,7 +50,7 @@
},
"tx_json": {
"Account": "rLSn6Z3T8uCxbcd1oxwfGQN1Fdn5CyGujK",
"Amount": "104169972",
"DeliverMax": "104169972",
"Destination": "rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh",
"DestinationTag": 109735445,
"Fee": "6000",

View File

@@ -3,41 +3,43 @@
"status": "success",
"type": "response",
"result": {
"Account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"Amount": {
"currency": "USD",
"issuer": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"value": "0.001"
"tx_json": {
"Account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"DeliverMax": {
"currency": "USD",
"issuer": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"value": "0.001"
},
"Destination": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"Fee": "10",
"Flags": 0,
"Paths": [
[
{
"currency": "USD",
"issuer": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"type": 48,
"type_hex": "0000000000000030"
},
{
"account": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"currency": "USD",
"issuer": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"type": 49,
"type_hex": "0000000000000031"
}
]
],
"SendMax": "1112209",
"Sequence": 4,
"SigningPubKey": "02BC8C02199949B15C005B997E7C8594574E9B02BA2D0628902E0532989976CF9D",
"TransactionType": "Payment",
"TxnSignature": "304502204EE3E9D1B01D8959B08450FCA9E22025AF503DEF310E34A93863A85CAB3C0BC5022100B61F5B567F77026E8DEED89EED0B7CAF0E6C96C228A2A65216F0DC2D04D52083",
"date": 416447810,
"inLedger": 348860,
"ledger_index": 348860,
"hash": "F4AB442A6D4CBB935D66E1DA7309A5FC71C7143ED4049053EC14E3875B0CF9BF"
},
"Destination": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"Fee": "10",
"Flags": 0,
"Paths": [
[
{
"currency": "USD",
"issuer": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"type": 48,
"type_hex": "0000000000000030"
},
{
"account": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"currency": "USD",
"issuer": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"type": 49,
"type_hex": "0000000000000031"
}
]
],
"SendMax": "1112209",
"Sequence": 4,
"SigningPubKey": "02BC8C02199949B15C005B997E7C8594574E9B02BA2D0628902E0532989976CF9D",
"TransactionType": "Payment",
"TxnSignature": "304502204EE3E9D1B01D8959B08450FCA9E22025AF503DEF310E34A93863A85CAB3C0BC5022100B61F5B567F77026E8DEED89EED0B7CAF0E6C96C228A2A65216F0DC2D04D52083",
"date": 416447810,
"hash": "F4AB442A6D4CBB935D66E1DA7309A5FC71C7143ED4049053EC14E3875B0CF9BF",
"inLedger": 348860,
"ledger_index": 348860,
"meta": {
"AffectedNodes": [
{

View File

@@ -1,7 +1,7 @@
To run integration tests:
1. Run rippled in standalone node, either in a docker container (preferred) or by installing rippled.
* Go to the top-level of the `xrpl.js` repo, just above the `packages` folder.
* With docker, run `docker run -p 6006:6006 --interactive -t --volume $PWD/.ci-config:/config/ xrpllabsofficial/1.12.0-b1 -a --start`
* With docker, run `docker run -p 6006:6006 --interactive -t --volume $PWD/.ci-config:/opt/ripple/etc/ --platform linux/amd64 rippleci/rippled:2.2.0-b3 /opt/ripple/bin/rippled -a --conf /opt/ripple/etc/rippled.cfg`
* Or [download and build rippled](https://xrpl.org/install-rippled.html) and run `./rippled -a --start`
* If you'd like to use the latest rippled amendments, you should modify your `rippled.cfg` file to enable amendments in the `[amendments]` section. You can view `.ci-config/rippled.cfg` in the top level folder as an example of this.
2. Run `npm run test:integration` or `npm run test:browser`

View File

@@ -83,40 +83,6 @@ describe('fundWallet', function () {
// )
// })
it(
'can generate wallet on hooks v3 testnet',
async function () {
const api = new Client('wss://hooks-testnet-v3.xrpl-labs.com')
await api.connect()
const { wallet, balance } = await api.fundWallet(null, {
usageContext: 'integration-test',
})
assert.notStrictEqual(wallet, undefined)
assert(isValidClassicAddress(wallet.classicAddress))
assert(isValidXAddress(wallet.getXAddress()))
const info = await api.request({
command: 'account_info',
account: wallet.classicAddress,
})
assert.equal(dropsToXrp(info.result.account_data.Balance), balance)
assert.equal(balance, 10000)
/*
* No test for fund given wallet because the hooks v3 testnet faucet
* requires 10 seconds between requests. Would significantly slow down
* the test suite.
*/
await api.disconnect()
},
TIMEOUT,
)
it(
'submit funds wallet with custom amount',
async function () {
@@ -124,10 +90,10 @@ describe('fundWallet', function () {
await api.connect()
const { wallet, balance } = await api.fundWallet(null, {
amount: '2000',
amount: '1000',
usageContext: 'integration-test',
})
assert.equal(balance, 2000)
assert.equal(balance, 1000)
assert.notStrictEqual(wallet, undefined)
assert(isValidClassicAddress(wallet.classicAddress))
assert(isValidXAddress(wallet.getXAddress()))

View File

@@ -80,4 +80,105 @@ describe('account_info', function () {
},
TIMEOUT,
)
it(
'uses api_version 1',
async () => {
const request: AccountInfoRequest = {
command: 'account_info',
account: testContext.wallet.classicAddress,
strict: true,
ledger_index: 'validated',
api_version: 1,
}
const response = await testContext.client.request(request)
const expected = {
id: 0,
result: {
account_data: {
Account: testContext.wallet.classicAddress,
Balance: '400000000',
Flags: 0,
LedgerEntryType: 'AccountRoot',
OwnerCount: 0,
PreviousTxnID:
'19A8211695785A3A02C1C287D93C2B049E83A9CD609825E721052D63FF4F0EC8',
PreviousTxnLgrSeq: 582,
Sequence: 283,
index:
'BD4815E6EB304136E6044F778FB68D4E464CC8DFC59B8F6CC93D90A3709AE194',
},
ledger_hash:
'F0DEEC46A7185BBB535517EE38CF2025973022D5B0532B36407F492521FDB0C6',
ledger_index: 582,
validated: true,
},
type: 'response',
}
assert.equal(response.type, expected.type)
assert.equal(response.result.validated, expected.result.validated)
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',
]),
)
},
TIMEOUT,
)
it(
'signer_list using api_version 1',
async () => {
const request: AccountInfoRequest = {
command: 'account_info',
account: testContext.wallet.classicAddress,
strict: true,
ledger_index: 'validated',
signer_lists: true,
api_version: 1,
}
const response = await testContext.client.request<AccountInfoRequest, 1>(
request,
)
expect(response.result.account_data.signer_lists).toEqual([])
// @ts-expect-error -- signer_lists is expected to be undefined
expect(response.result.signer_lists).toBeUndefined()
},
TIMEOUT,
)
it(
'signer_list using api_version 2',
async () => {
const request: AccountInfoRequest = {
command: 'account_info',
account: testContext.wallet.classicAddress,
strict: true,
ledger_index: 'validated',
signer_lists: true,
}
const response = await testContext.client.request(request)
// @ts-expect-error -- signer_lists is expected to be undefined
expect(response.result.account_data.signer_lists).toBeUndefined()
expect(response.result.signer_lists).toEqual([])
},
TIMEOUT,
)
})

View File

@@ -32,6 +32,102 @@ describe('account_tx', function () {
ledger_index: 'validated',
}
const response = await testContext.client.request(request)
const expected = {
result: {
account: testContext.wallet.classicAddress,
limit: 400,
transactions: [
{
tx_json: {
Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
DeliverMax: '400000000',
Destination: testContext.wallet.classicAddress,
Fee: '12',
Flags: 0,
LastLedgerSequence: 1753,
Sequence: 843,
SigningPubKey:
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020',
TransactionType: 'Payment',
TxnSignature:
'30440220693D244BC13967E3DA67BDC974096784ED03DD4ACE6F36645E5176988452AFCF02200F8AB172432913899F27EC5523829AEDAD00CC2445690400E294EDF652A85945',
date: 685747005,
hash: '2E68BC15813B4A836FAC4D80E42E6FDA6410E99AB973937DEA5E6C2E9A116BAB',
ledger_index: 1734,
},
},
],
},
type: 'response',
}
assert.equal(response.type, expected.type)
assert.equal(response.result.account, expected.result.account)
assert.equal(
(response.result.transactions[0].meta as TransactionMetadata<Payment>)
.TransactionResult,
'tesSUCCESS',
)
assert.equal(
typeof response.result.transactions[0].tx_json?.LastLedgerSequence,
'number',
)
assert.equal(
typeof response.result.transactions[0].tx_json?.Sequence,
'number',
)
assert.equal(
typeof response.result.transactions[0].tx_json?.SigningPubKey,
'string',
)
assert.equal(
typeof response.result.transactions[0].tx_json?.TxnSignature,
'string',
)
assert.equal(
typeof response.result.transactions[0].tx_json?.Fee,
'string',
)
assert.equal(typeof response.result.transactions[0].hash, 'string')
assert.equal(
typeof response.result.transactions[0].tx_json?.ledger_index,
'number',
)
const responseTx = response.result.transactions[0].tx_json as Payment
const expectedTx = expected.result.transactions[0].tx_json
assert.deepEqual(
[
responseTx.Flags,
responseTx.TransactionType,
responseTx.Account,
// @ts-expect-error -- DeliverMax is a valid field on Payment response
responseTx.DeliverMax,
responseTx.Destination,
],
[
expectedTx.Flags,
expectedTx.TransactionType,
expectedTx.Account,
expectedTx.DeliverMax,
expectedTx.Destination,
],
)
},
TIMEOUT,
)
it(
'uses api_version 1',
async () => {
const request: AccountTxRequest = {
command: 'account_tx',
account: testContext.wallet.classicAddress,
ledger_index: 'validated',
api_version: 1,
}
const response = await testContext.client.request<AccountTxRequest, 1>(
request,
)
const expected = {
result: {
account: testContext.wallet.classicAddress,

View File

@@ -35,6 +35,7 @@ describe('book_offers', function () {
const response = await testContext.client.request(bookOffer)
const expectedResponse: BookOffersResponse = {
api_version: 2,
id: response.id,
type: 'response',
result: {

View File

@@ -35,6 +35,7 @@ describe('channel_verify', function () {
const response = await testContext.client.request(channelVerify)
const expectedResponse: ChannelVerifyResponse = {
api_version: 2,
id: response.id,
type: 'response',
result: {

View File

@@ -36,6 +36,7 @@ describe('deposit_authorized', function () {
const response = await testContext.client.request(depositAuthorized)
const expectedResponse: DepositAuthorizedResponse = {
api_version: 2,
id: response.id,
type: 'response',
result: {

View File

@@ -0,0 +1,68 @@
import { assert } from 'chai'
import { FeatureRequest } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupClient,
teardownClient,
type XrplIntegrationTestContext,
} from '../setup'
// how long before each test case times out
const TIMEOUT = 20000
const AMENDMENT =
'8CC0774A3BF66D1D22E76BBDA8E8A232E6B6313834301B3B23E8601196AE6455'
describe('feature', function () {
let testContext: XrplIntegrationTestContext
beforeEach(async () => {
testContext = await setupClient(serverUrl)
})
afterEach(async () => teardownClient(testContext))
it(
'all',
async () => {
const featureRequest: FeatureRequest = {
command: 'feature',
}
const featureResponse = await testContext.client.request(featureRequest)
assert.equal(featureResponse.type, 'response')
assert.typeOf(featureResponse.result.features, 'object')
assert.isTrue(AMENDMENT in featureResponse.result.features)
const amendmentData = featureResponse.result.features[AMENDMENT]
assert.equal(amendmentData.name, 'AMM')
// TODO: rippled says "false" for standalone nodes for some reason
assert.typeOf(amendmentData.enabled, 'boolean')
assert.equal(amendmentData.supported, true)
},
TIMEOUT,
)
it(
'one',
async () => {
const featureRequest: FeatureRequest = {
command: 'feature',
feature: AMENDMENT,
}
const featureResponse = await testContext.client.request(featureRequest)
assert.equal(featureResponse.type, 'response')
assert.typeOf(featureResponse.result, 'object')
assert.isTrue(AMENDMENT in featureResponse.result)
assert.lengthOf(Object.keys(featureResponse.result), 1)
const amendmentData = featureResponse.result[AMENDMENT]
assert.equal(amendmentData.name, 'AMM')
// TODO: rippled says "false" for standalone nodes for some reason
assert.typeOf(amendmentData.enabled, 'boolean')
assert.equal(amendmentData.supported, true)
},
TIMEOUT,
)
})

View File

@@ -0,0 +1,78 @@
import { stringToHex } from '@xrplf/isomorphic/utils'
import { assert } from 'chai'
import { OracleSet } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupClient,
teardownClient,
type XrplIntegrationTestContext,
} from '../setup'
import { testTransaction } from '../utils'
// how long before each test case times out
const TIMEOUT = 20000
describe('get_aggregate_price', function () {
let testContext: XrplIntegrationTestContext
beforeEach(async () => {
testContext = await setupClient(serverUrl)
})
afterEach(async () => teardownClient(testContext))
it(
'base',
async () => {
const tx: OracleSet = {
TransactionType: 'OracleSet',
Account: testContext.wallet.classicAddress,
OracleDocumentID: 1234,
LastUpdateTime: Math.floor(Date.now() / 1000),
PriceDataSeries: [
{
PriceData: {
BaseAsset: 'XRP',
QuoteAsset: 'USD',
AssetPrice: 740,
Scale: 3,
},
},
],
Provider: stringToHex('chainlink'),
URI: '6469645F6578616D706C65',
AssetClass: stringToHex('currency'),
}
await testTransaction(testContext.client, tx, testContext.wallet)
// confirm that the Oracle was actually created
const getAggregatePriceResponse = await testContext.client.request({
command: 'get_aggregate_price',
account: testContext.wallet.classicAddress,
base_asset: 'XRP',
quote_asset: 'USD',
trim: 20,
oracles: [
{
account: testContext.wallet.classicAddress,
oracle_document_id: 1234,
},
],
})
assert.deepEqual(getAggregatePriceResponse.result.entire_set, {
mean: '0.74',
size: 1,
standard_deviation: '0',
})
assert.deepEqual(getAggregatePriceResponse.result.trimmed_set, {
mean: '0.74',
size: 1,
standard_deviation: '0',
})
assert.equal(getAggregatePriceResponse.result.median, '0.74')
assert.equal(getAggregatePriceResponse.result.time, tx.LastUpdateTime)
},
TIMEOUT,
)
})

View File

@@ -1,7 +1,7 @@
import { assert } from 'chai'
import { LedgerRequest, LedgerResponse } from '../../../src'
import { Ledger } from '../../../src/models/ledger'
import { LedgerRequest } from '../../../src'
import { Ledger, LedgerV1 } from '../../../src/models/ledger'
import serverUrl from '../serverUrl'
import {
setupClient,
@@ -29,6 +29,7 @@ describe('ledger', function () {
}
const expected = {
api_version: 2,
id: 0,
result: {
ledger: {
@@ -45,7 +46,68 @@ describe('ledger', function () {
type: 'response',
}
const ledgerResponse: LedgerResponse = await testContext.client.request(
const ledgerResponse = await testContext.client.request(ledgerRequest)
assert.equal(ledgerResponse.type, expected.type)
assert.equal(ledgerResponse.result.validated, expected.result.validated)
assert.typeOf(ledgerResponse.result.ledger_hash, 'string')
assert.typeOf(ledgerResponse.result.ledger_index, 'number')
const ledger = ledgerResponse.result.ledger as Ledger & {
accepted: boolean
hash: string
seqNum: string
}
assert.equal(ledger.closed, true)
const stringTypes = [
'account_hash',
'close_time_human',
'ledger_hash',
'parent_hash',
'total_coins',
'transaction_hash',
]
stringTypes.forEach((strType) => assert.typeOf(ledger[strType], 'string'))
const numTypes = [
'close_flags',
'close_time',
'close_time_resolution',
'ledger_index',
'parent_close_time',
]
numTypes.forEach((numType) => assert.typeOf(ledger[numType], 'number'))
},
TIMEOUT,
)
it(
'uses api_version 1',
async () => {
const ledgerRequest: LedgerRequest = {
command: 'ledger',
ledger_index: 'validated',
api_version: 1,
}
const expected = {
id: 0,
result: {
ledger: {
accepted: true,
account_hash: 'string',
close_flags: 0,
close_time: 0,
close_time_human: 'string',
},
ledger_hash: 'string',
ledger_index: 1,
validated: true,
},
type: 'response',
}
const ledgerResponse = await testContext.client.request<LedgerRequest, 1>(
ledgerRequest,
)
@@ -55,7 +117,7 @@ describe('ledger', function () {
assert.typeOf(ledgerResponse.result.ledger_hash, 'string')
assert.typeOf(ledgerResponse.result.ledger_index, 'number')
const ledger = ledgerResponse.result.ledger as Ledger & {
const ledger = ledgerResponse.result.ledger as LedgerV1 & {
accepted: boolean
hash: string
seqNum: string

View File

@@ -40,6 +40,7 @@ describe('ledger_entry', function () {
)
const expectedResponse: LedgerEntryResponse = {
api_version: 2,
id: ledgerEntryResponse.id,
type: 'response',
result: {

View File

@@ -41,6 +41,7 @@ describe('path_find', function () {
const response = await testContext.client.request(pathFind)
const expectedResponse: PathFindResponse = {
api_version: 2,
id: response.id,
type: 'response',
result: {
@@ -98,6 +99,7 @@ describe('path_find', function () {
const response = await testContext.client.request(pathFind)
const expectedResponse: PathFindResponse = {
api_version: 2,
id: response.id,
type: 'response',
result: {

View File

@@ -35,6 +35,7 @@ describe('ripple_path_find', function () {
const response = await testContext.client.request(ripplePathFind)
const expectedResponse: RipplePathFindResponse = {
api_version: 2,
id: response.id,
type: 'response',
result: {

View File

@@ -54,6 +54,7 @@ describe('submit', function () {
)
const expectedResponse: SubmitResponse = {
api_version: 2,
id: submitResponse.id,
type: 'response',
result: {

View File

@@ -8,6 +8,8 @@ import {
Transaction,
SubmitMultisignedResponse,
hashes,
SubmitMultisignedRequest,
SubmitMultisignedV1Response,
} from '../../../src'
import { convertStringToHex } from '../../../src/utils'
import { multisign } from '../../../src/Wallet/signer'
@@ -88,6 +90,81 @@ describe('submit_multisigned', function () {
await verifySubmittedTransaction(testContext.client, multisigned)
const expectedResponse: SubmitMultisignedResponse = {
api_version: 2,
id: submitResponse.id,
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: hashSignedTx(multisigned),
},
}
assert.deepEqual(submitResponse, expectedResponse)
},
TIMEOUT,
)
it(
'submit_multisigned transaction using api_version 1',
async () => {
const client: Client = testContext.client
const signerWallet1 = await generateFundedWallet(testContext.client)
const signerWallet2 = await generateFundedWallet(testContext.client)
// set up the multisigners for the account
const signerListSet: SignerListSet = {
TransactionType: 'SignerListSet',
Account: testContext.wallet.classicAddress,
SignerEntries: [
{
SignerEntry: {
Account: signerWallet1.classicAddress,
SignerWeight: 1,
},
},
{
SignerEntry: {
Account: signerWallet2.classicAddress,
SignerWeight: 1,
},
},
],
SignerQuorum: 2,
}
await testTransaction(
testContext.client,
signerListSet,
testContext.wallet,
)
// try to multisign
const accountSet: AccountSet = {
TransactionType: 'AccountSet',
Account: testContext.wallet.classicAddress,
Domain: convertStringToHex('example.com'),
}
const accountSetTx = await client.autofill(accountSet, 2)
const signed1 = signerWallet1.sign(accountSetTx, true)
const signed2 = signerWallet2.sign(accountSetTx, true)
const multisigned = multisign([signed1.tx_blob, signed2.tx_blob])
const submitResponse = await client.request<SubmitMultisignedRequest, 1>({
command: 'submit_multisigned',
tx_json: decode(multisigned) as unknown as Transaction,
api_version: 1,
})
await ledgerAccept(client)
assert.strictEqual(submitResponse.result.engine_result, 'tesSUCCESS')
await verifySubmittedTransaction(testContext.client, multisigned)
const expectedResponse: SubmitMultisignedV1Response = {
api_version: 1,
id: submitResponse.id,
type: 'response',
result: {

View File

@@ -1,6 +1,13 @@
import { assert } from 'chai'
import { AccountSet, hashes, SubmitResponse, TxResponse } from '../../../src'
import {
AccountSet,
hashes,
SubmitResponse,
TxRequest,
TxResponse,
TxV1Response,
} from '../../../src'
import { convertStringToHex } from '../../../src/utils'
import serverUrl from '../serverUrl'
import {
@@ -45,17 +52,20 @@ describe('tx', function () {
})
const expectedResponse: TxResponse = {
api_version: 2,
id: txResponse.id,
type: 'response',
result: {
...accountSet,
Fee: txResponse.result.Fee,
Flags: 0,
LastLedgerSequence: txResponse.result.LastLedgerSequence,
Sequence: txResponse.result.Sequence,
SigningPubKey: testContext.wallet.publicKey,
TxnSignature: txResponse.result.TxnSignature,
hash: hashSignedTx(response.result.tx_blob),
tx_json: {
...accountSet,
Fee: txResponse.result.tx_json.Fee,
Flags: 0,
LastLedgerSequence: txResponse.result.tx_json.LastLedgerSequence,
Sequence: txResponse.result.tx_json.Sequence,
SigningPubKey: testContext.wallet.publicKey,
TxnSignature: txResponse.result.tx_json.TxnSignature,
},
validated: false,
},
}
@@ -64,4 +74,50 @@ describe('tx', function () {
},
TIMEOUT,
)
it(
'uses api_version 1',
async () => {
const account = testContext.wallet.classicAddress
const accountSet: AccountSet = {
TransactionType: 'AccountSet',
Account: account,
Domain: convertStringToHex('example.com'),
}
const response: SubmitResponse = await testContext.client.submit(
accountSet,
{
wallet: testContext.wallet,
},
)
const hash = hashSignedTx(response.result.tx_blob)
const txV1Response = await testContext.client.request<TxRequest, 1>({
command: 'tx',
transaction: hash,
api_version: 1,
})
const expectedResponse: TxV1Response = {
api_version: 1,
id: txV1Response.id,
type: 'response',
result: {
...accountSet,
Fee: txV1Response.result.Fee,
Flags: 0,
LastLedgerSequence: txV1Response.result.LastLedgerSequence,
Sequence: txV1Response.result.Sequence,
SigningPubKey: testContext.wallet.publicKey,
TxnSignature: txV1Response.result.TxnSignature,
hash: hashSignedTx(response.result.tx_blob),
validated: false,
},
}
assert.deepEqual(txV1Response, expectedResponse)
},
TIMEOUT,
)
})

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