Compare commits

..

100 Commits

Author SHA1 Message Date
Omar Khan
11e724253b 4.1.0 release (#2851)
* update HISTORY

* update package-lock

* update ripple-binary-codec HISTORY

* update release dates

* update release dates

* update HISTORY files
2024-12-21 07:10:25 +05:30
achowdhry-ripple
f34d1a7a63 Credentials (#2829)
* create credentials obj, modify depositpreauth

* structrure of transaction models

* initial validation methods and modify transactions affected by deposit auth

* cleanup and add new transactions to list

* binarycodec and add amendments to config

* methods account for credentials

* binary codec update

* add amendments to config

* error validation for credentials actions

* core logic of error validation completed

* type checking in error validation

* init test files and field type validations

* basic tests for crud transactions

* cred delete tests

* cred accept unit tests

* cred create and accept unit tests

* cred delete unit tests

* depositPreauth unit tests

* generic checks for payment, paymentchannelclaim, escrowfinish credential list

* ledger entry update

* lint errors

* cleanup and use helper methods

* fix lint bug

* init integration tests for new transactions

* fix build error, integration test docker update

* unit test fixes -- all pass now

* integration test layout complete

* integration command

* integration tests run

* cicd command edit

* lint and cleanup

* modified history markdown

* deposit preauth integration update

* update docs with new docker command

* fix validation for string id credential arrays

* exports

* add flag

* lint

* fix typo in contributing doc

* docstring typos

* readable string

* fix test'

* review comment fixes

* txn duplicate fix

* Apply suggestions from code review

Co-authored-by: Omar Khan <khancodegt@gmail.com>
Co-authored-by: Mayukha Vadari <mvadari@ripple.com>

* Apply suggestions from code review

Co-authored-by: Omar Khan <khancodegt@gmail.com>

* Apply suggestions from code review

Co-authored-by: Omar Khan <khancodegt@gmail.com>
Co-authored-by: Mayukha Vadari <mvadari@ripple.com>

* typo in auto suggest

* rebase

* readd definitions after rebase

* cleanup list val

* unit tests fixed and running

* lint

* refactor authcred check to work

* Update packages/xrpl/src/models/transactions/payment.ts

Co-authored-by: Omar Khan <khancodegt@gmail.com>

* typo

* Update .ci-config/rippled.cfg

Co-authored-by: Omar Khan <khancodegt@gmail.com>

* update rippled version

* optional field nits

* add to response depositauthorize

* Update packages/xrpl/src/models/transactions/CredentialCreate.ts

Co-authored-by: Omar Khan <khancodegt@gmail.com>

* Update packages/xrpl/src/models/transactions/CredentialDelete.ts

Co-authored-by: Omar Khan <khancodegt@gmail.com>

* Update packages/xrpl/src/models/transactions/accountDelete.ts

Co-authored-by: Omar Khan <khancodegt@gmail.com>

* Apply suggestions from code review

Co-authored-by: Omar Khan <khancodegt@gmail.com>

* cleanups

* unit test fix

* more escrowfinish tests

* clearer error message

* re add statement

* undo autodeleted mandates

* remove extraneous integration tests for now

* lint

* Update .ci-config/rippled.cfg

Co-authored-by: Omar Khan <khancodegt@gmail.com>

* Update packages/xrpl/src/models/transactions/common.ts

Co-authored-by: Omar Khan <khancodegt@gmail.com>

* added tests

* typo

---------

Co-authored-by: Omar Khan <khancodegt@gmail.com>
Co-authored-by: Mayukha Vadari <mvadari@ripple.com>
2024-12-20 14:03:56 -05:00
Shawn Xie
7bf6fecc71 add more mpt flag validations (#2856)
* remove else condition

* validation txfee

* clidation

* lint

* lint

* comments

* lint

* more typechecking

* rm newline

* refactor

* null check

* revert null check

* reuse test
2024-12-19 15:53:16 -05:00
dependabot[bot]
303c2b983c build(deps): bump @scure/bip32 from 1.5.0 to 1.6.0 (#2852) 2024-12-16 20:26:32 +00:00
Mayukha Vadari
448164da70 chore: bump Github Actions versions (#2788)
bump Github Actions versions
2024-12-13 12:17:21 -08:00
dependabot[bot]
9f72c8d384 build(deps): bump @scure/base from 1.1.9 to 1.2.1 (#2844) 2024-12-12 01:12:16 +00:00
Mayukha Vadari
e42d418662 feat: add node v22 and npm v10 support (#2695)
* add node 22 support

* add debug stuff

* try upgrading npm

* remove node 16

* debug

* remove tmux

* only allow 22.9 onwards

* try 22.8

* try 22.7

* test more 22.x versions

* test more versions

* switch back to 22.x, clean up

* update README
2024-12-11 16:50:41 -08:00
dependabot[bot]
305f2c48bf build(deps): bump @noble/curves from 1.6.0 to 1.7.0 (#2836)
Bumps [@noble/curves](https://github.com/paulmillr/noble-curves) from 1.6.0 to 1.7.0.
- [Release notes](https://github.com/paulmillr/noble-curves/releases)
- [Commits](https://github.com/paulmillr/noble-curves/compare/1.6.0...1.7.0)

---
updated-dependencies:
- dependency-name: "@noble/curves"
  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-12-11 16:00:54 -08:00
dependabot[bot]
b7dfcbf075 build(deps-dev): bump react from 18.3.1 to 19.0.0 (#2843) 2024-12-11 23:37:09 +00:00
Shawn Xie
b04efe8c9e MPT (#2661)
MPT Support for library and binary codec
2024-12-11 13:38:13 -08:00
dependabot[bot]
e3188b83ed build(deps): bump @noble/hashes from 1.5.0 to 1.6.1 (#2837)
Bumps [@noble/hashes](https://github.com/paulmillr/noble-hashes) from 1.5.0 to 1.6.1.
- [Release notes](https://github.com/paulmillr/noble-hashes/releases)
- [Commits](https://github.com/paulmillr/noble-hashes/compare/1.5.0...1.6.1)

---
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-12-09 20:35:54 +05:30
dependabot[bot]
f4011b58e7 build(deps): bump @scure/bip39 from 1.4.0 to 1.5.0 (#2838)
Bumps [@scure/bip39](https://github.com/paulmillr/scure-bip39) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/paulmillr/scure-bip39/releases)
- [Commits](https://github.com/paulmillr/scure-bip39/compare/1.4.0...1.5.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>
Co-authored-by: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com>
2024-12-09 16:03:25 +05:30
Emmanuel Ferdman
00614753ff docs: update references in CONTRIBUTING.md (#2832)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2024-12-04 18:41:50 -05:00
Denis Angell
b3a76bd9c0 Update HISTORY.md (#2777) 2024-12-02 15:17:02 -05:00
dependabot[bot]
24e9ad7c12 build(deps-dev): bump webpack from 5.95.0 to 5.96.1 (#2833) 2024-11-21 20:54:39 +00:00
Shawn Xie
c2dd2edbcc Update custom Payment to a higher number in binary codec test (#2824)
* update payment custom def

* comment
2024-11-18 17:34:12 -05:00
dependabot[bot]
c9207337aa build(deps-dev): bump typedoc from 0.26.10 to 0.26.11 (#2822)
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.26.10 to 0.26.11.
- [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.10...v0.26.11)

---
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>
Co-authored-by: Omar Khan <khancodegt@gmail.com>
2024-11-15 15:29:12 -05:00
dependabot[bot]
a6852dd588 build(deps-dev): bump @types/jest from 29.5.12 to 29.5.14 (#2821)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 29.5.12 to 29.5.14.
- [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>
Co-authored-by: Omar Khan <khancodegt@gmail.com>
2024-11-15 15:06:26 -05:00
dependabot[bot]
3a604ce69a build(deps-dev): bump @types/lodash from 4.17.12 to 4.17.13 (#2819)
Bumps [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) from 4.17.12 to 4.17.13.
- [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>
Co-authored-by: Omar Khan <khancodegt@gmail.com>
2024-11-15 14:59:19 -05:00
justinr1234
663b80f1d0 chore: remove code rabbit sequence diagram (#2827) 2024-11-14 12:40:46 -06:00
dependabot[bot]
92eb809397 build(deps): bump @noble/hashes from 1.4.0 to 1.5.0 (#2814)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: justinr1234 <justinr1234@gmail.com>
Co-authored-by: anissa-ripple <165064424+anissa-ripple@users.noreply.github.com>
2024-11-04 11:15:03 -06:00
dependabot[bot]
799cd65386 build(deps): bump @scure/bip39 from 1.3.0 to 1.4.0 (#2813)
Bumps [@scure/bip39](https://github.com/paulmillr/scure-bip39) from 1.3.0 to 1.4.0.
- [Release notes](https://github.com/paulmillr/scure-bip39/releases)
- [Commits](https://github.com/paulmillr/scure-bip39/compare/1.3.0...1.4.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>
Co-authored-by: anissa-ripple <165064424+anissa-ripple@users.noreply.github.com>
Co-authored-by: justinr1234 <justinr1234@gmail.com>
2024-11-04 08:28:33 -08:00
dependabot[bot]
29d145138b build(deps-dev): bump eslint-plugin-import from 2.29.1 to 2.31.0 (#2799)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: anissa-ripple <165064424+anissa-ripple@users.noreply.github.com>
2024-11-04 10:10:51 -06:00
Mayukha Vadari
496f774154 fix: resolve TransactionStream and Ledger model issues (#2779)
* update TransactionStream model

* fix everywhere else

* add close_time_iso

* add close_time_iso to TransactionStream

* update HISTORY

* fix tests

* fix import

* Update packages/xrpl/src/client/partialPayment.ts
2024-11-04 10:55:47 -05:00
dependabot[bot]
0395c14392 build(deps-dev): bump @types/lodash from 4.17.7 to 4.17.12 (#2810) 2024-10-21 16:23:46 +00:00
dependabot[bot]
2a77e2cd91 build(deps-dev): bump typedoc from 0.26.9 to 0.26.10 (#2809) 2024-10-21 16:17:27 +00:00
dependabot[bot]
619c9ae13a build(deps-dev): bump typedoc from 0.26.7 to 0.26.9 (#2803) 2024-10-16 14:30:07 +00:00
Mayukha Vadari
8beb1292b5 fix: make transaction-generating scripts more robust (#2690)
* improve scripts

* Update settings.json

* update file locations after refactor
2024-10-11 14:40:19 -07:00
dependabot[bot]
649bf7d277 build(deps): bump @scure/bip32 from 1.4.0 to 1.5.0 (#2791) 2024-10-02 00:37:54 +00:00
dependabot[bot]
e0d368791b build(deps-dev): bump eslint from 8.57.0 to 8.57.1 (#2792) 2024-10-01 21:01:32 +00:00
Zhiyuan Wang
be9b48b071 Add include_deleted param to ledger_entry API (#2725)
* 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

* add include_deleted field

* update history

* fix an error in histroy

* changed comments

---------

Authored-by: Kassaking <kassaking7@gmail.com>
2024-10-01 16:54:00 -04:00
dependabot[bot]
55892c8b89 build(deps-dev): bump webpack from 5.93.0 to 5.95.0 (#2785) 2024-09-26 19:34:40 +00:00
dependabot[bot]
b1b4995047 build(deps): bump @noble/curves from 1.4.0 to 1.6.0 (#2769)
Bumps [@noble/curves](https://github.com/paulmillr/noble-curves) from 1.4.0 to 1.6.0.
- [Release notes](https://github.com/paulmillr/noble-curves/releases)
- [Commits](https://github.com/paulmillr/noble-curves/compare/1.4.0...1.6.0)

---
updated-dependencies:
- dependency-name: "@noble/curves"
  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-09-26 15:21:25 -04:00
dependabot[bot]
a726a5a4f9 build(deps-dev): bump typedoc from 0.26.4 to 0.26.7 (#2772)
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.26.4 to 0.26.7.
- [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.4...v0.26.7)

---
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-09-26 15:08:41 -04:00
Chenna Keshava B S
8992d3914e remove bridge snippet test, the sidechain has been shut down (#2773)
* update Paths snippet test: perform prerequisite test setup within the test, remove dependence on theexternal state of testnet

* remove bridge snippet test, the sidechain has been shut down

* [FIX] Update paths snippet. Replace RipplePathFind with PathFind RPC (fixes #2385)
2024-09-26 14:07:56 -04:00
justinr1234
c2e01b3d10 feat: coderabbit.ai config (#2781) 2024-09-19 16:07:23 -05:00
Mayukha Vadari
8bfe5b42b8 chore: fix CodeQL issue (#2727)
fix CodeQL issue
2024-09-19 15:00:06 -04:00
Chenna Keshava B S
385a56a1f7 update Paths snippet test (#2765)
* update Paths snippet test: perform prerequisite test setup within the test, remove dependence on theexternal state of testnet

* fix lint errors

* remove bridge snippet test, the sidechain has been shut down

* [FIX] Update paths snippet. Replace RipplePathFind with PathFind RPC (fixes #2385)
2024-09-19 13:23:55 -05:00
achowdhry-ripple
f3960c3ccc Parse transaction flags into map of names:booleans (#2734)
* overview logic of parsetransactionflags

* parse transaction flags works

* basic tests

* eslint and docs

* linting

* lint

* fix typing

* test fix

* revert import delete

* lint

* integration fix

* lint

* imports

* added numeric test

* add history log

* history update
2024-08-07 11:44:57 -04:00
dependabot[bot]
a46e86f17e build(deps-dev): bump @types/lodash from 4.17.1 to 4.17.7 (#2745) 2024-07-24 15:49:13 +00:00
dependabot[bot]
8f5d210806 build(deps-dev): bump webpack from 5.92.1 to 5.93.0 (#2731)
Bumps [webpack](https://github.com/webpack/webpack) from 5.92.1 to 5.93.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.92.1...v5.93.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-07-17 14:01:09 -07:00
dependabot[bot]
17c91cdd3a build(deps-dev): bump typedoc from 0.26.3 to 0.26.4 (#2732)
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.26.3 to 0.26.4.
- [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.3...v0.26.4)

---
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>
Co-authored-by: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com>
2024-07-17 13:54:08 -07:00
dependabot[bot]
74a41832ce build(deps-dev): bump ts-jest from 29.2.0 to 29.2.2 (#2733)
Bumps [ts-jest](https://github.com/kulshekhar/ts-jest) from 29.2.0 to 29.2.2.
- [Release notes](https://github.com/kulshekhar/ts-jest/releases)
- [Changelog](https://github.com/kulshekhar/ts-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/kulshekhar/ts-jest/compare/v29.2.0...v29.2.2)

---
updated-dependencies:
- dependency-name: ts-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-07-17 13:47:00 -07:00
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
178 changed files with 10816 additions and 16966 deletions

View File

@@ -170,3 +170,21 @@ fixNFTokenRemint
# 2.0.0 Amendments # 2.0.0 Amendments
XChainBridge XChainBridge
DID DID
# 2.2.0-b3 Amendments
fixNFTokenReserve
fixInnerObjTemplate
fixAMMOverflowOffer
PriceOracle
fixEmptyDID
fixXChainRewardRounding
fixPreviousTxnID
fixAMMv1_1
# 2.3.0 Amendments
fixAMMv1_2
Credentials
NFTokenMintOffer
MPTokensV1
fixNFTokenPageLinks
fixInnerObjTemplate2
fixEnforceNFTokenTrustline
fixReducedOffersV2

30
.coderabbit.yaml Normal file
View File

@@ -0,0 +1,30 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
language: "en-US"
reviews:
# Set the profile for reviews. Assertive profile yields more feedback, that may be considered nitpicky.
profile: "chill"
# Approve the review once CodeRabbit's comments are resolved. Note: In GitLab, all discussions must be resolved.
request_changes_workflow: false
# Generate a high level summary of the changes in the PR/MR description.
high_level_summary: false
# Generate a poem in the walkthrough comment.
poem: true
# Post review details on each review. Additionally, post a review status when a review is skipped in certain cases.
review_status: true
# Generate walkthrough in a markdown collapsible section.
collapse_walkthrough: false
# Generate sequence diagrams in the walkthrough.
sequence_diagrams: false
# Abort the in-progress review if the pull request is closed or merged.
abort_on_close: true
auto_review:
# Automatic Review | Automatic code review
enabled: true
# Review draft PRs/MRs.
drafts: false
# Ignore reviewing if the title of the pull request contains any of these keywords (case-insensitive).
ignore_title_keywords:
- build(
chat:
# Enable the bot to reply automatically without requiring the user to tag it.
auto_reply: true

View File

@@ -12,13 +12,11 @@
name: "CodeQL" name: "CodeQL"
on: on:
push:
branches: [ main, 1.x ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ main ] branches: [main]
schedule: schedule:
- cron: '44 5 * * 6' - cron: "44 5 * * 6"
jobs: jobs:
analyze: analyze:
@@ -28,40 +26,40 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
language: [ 'javascript' ] language: ["javascript"]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more: # Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v2 uses: github/codeql-action/init@v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file. # By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file. # Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main # queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v2 uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project # and modify them (or add more) to build your code if your project
# uses a compiled language # uses a compiled language
#- run: | #- run: |
# make bootstrap # make bootstrap
# make release # make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v3

View File

@@ -4,7 +4,7 @@
name: Node.js CI name: Node.js CI
env: env:
RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.0.0-b4 RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.3.0-rc1
on: on:
push: push:
@@ -19,22 +19,22 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [16.x] node-version: [18.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Setup npm version 9 - name: Setup npm version 10
run: | run: |
npm i -g npm@9 --registry=https://registry.npmjs.org npm i -g npm@10 --registry=https://registry.npmjs.org
- name: Cache node modules - name: Cache node modules
id: cache-nodemodules id: cache-nodemodules
uses: actions/cache@v3 uses: actions/cache@v4
env: env:
cache-name: cache-node-modules cache-name: cache-node-modules
with: with:
@@ -45,7 +45,6 @@ jobs:
key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: | restore-keys: |
${{ runner.os }}-deps-${{ matrix.node-version }}- ${{ runner.os }}-deps-${{ matrix.node-version }}-
${{ runner.os }}-deps-
- name: Install Dependencies - name: Install Dependencies
if: steps.cache-nodemodules.outputs.cache-hit != 'true' if: steps.cache-nodemodules.outputs.cache-hit != 'true'
@@ -60,22 +59,22 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [16.x, 18.x, 20.x] node-version: [18.x, 20.x, 22.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Setup npm version 9 - name: Setup npm version 10
run: | run: |
npm i -g npm@9 --registry=https://registry.npmjs.org npm i -g npm@10 --registry=https://registry.npmjs.org
- name: Cache node modules - name: Cache node modules
id: cache-nodemodules id: cache-nodemodules
uses: actions/cache@v3 uses: actions/cache@v4
env: env:
cache-name: cache-node-modules cache-name: cache-node-modules
with: with:
@@ -86,7 +85,6 @@ jobs:
key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: | restore-keys: |
${{ runner.os }}-deps-${{ matrix.node-version }}- ${{ runner.os }}-deps-${{ matrix.node-version }}-
${{ runner.os }}-deps-
- name: Install Dependencies - name: Install Dependencies
if: steps.cache-nodemodules.outputs.cache-hit != 'true' if: steps.cache-nodemodules.outputs.cache-hit != 'true'
@@ -101,27 +99,27 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [16.x, 18.x, 20.x] node-version: [18.x, 20.x, 22.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Run docker in background - name: Run docker in background
run: | run: |
docker run --detach --rm --name rippled-service -p 6006:6006 --volume "${{ github.workspace }}/.ci-config/":"/opt/ripple/etc/" --health-cmd="wget localhost:6006 || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s --env GITHUB_ACTIONS=true --env CI=true ${{ env.RIPPLED_DOCKER_IMAGE }} /opt/ripple/bin/rippled -a --conf /opt/ripple/etc/rippled.cfg docker run --detach --rm -p 6006:6006 --volume "${{ github.workspace }}/.ci-config/":"/etc/opt/ripple/" --name rippled-service --health-cmd="rippled server_info || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s --env GITHUB_ACTIONS=true --env CI=true --entrypoint bash ${{ env.RIPPLED_DOCKER_IMAGE }} -c "rippled -a"
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Setup npm version 9 - name: Setup npm version 10
run: | run: |
npm i -g npm@9 --registry=https://registry.npmjs.org npm i -g npm@10 --registry=https://registry.npmjs.org
- name: Cache node modules - name: Cache node modules
id: cache-nodemodules id: cache-nodemodules
uses: actions/cache@v3 uses: actions/cache@v4
env: env:
cache-name: cache-node-modules cache-name: cache-node-modules
with: with:
@@ -132,7 +130,6 @@ jobs:
key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: | restore-keys: |
${{ runner.os }}-deps-${{ matrix.node-version }}- ${{ runner.os }}-deps-${{ matrix.node-version }}-
${{ runner.os }}-deps-
- name: Install Dependencies - name: Install Dependencies
if: steps.cache-nodemodules.outputs.cache-hit != 'true' if: steps.cache-nodemodules.outputs.cache-hit != 'true'
@@ -153,27 +150,27 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [16.x] node-version: [18.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Run docker in background - name: Run docker in background
run: | run: |
docker run --detach --rm --name rippled-service -p 6006:6006 --volume "${{ github.workspace }}/.ci-config/":"/opt/ripple/etc/" --health-cmd="wget localhost:6006 || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s --env GITHUB_ACTIONS=true --env CI=true ${{ env.RIPPLED_DOCKER_IMAGE }} /opt/ripple/bin/rippled -a --conf /opt/ripple/etc/rippled.cfg docker run --detach --rm -p 6006:6006 --volume "${{ github.workspace }}/.ci-config/":"/etc/opt/ripple/" --name rippled-service --health-cmd="rippled server_info || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s --env GITHUB_ACTIONS=true --env CI=true --entrypoint bash ${{ env.RIPPLED_DOCKER_IMAGE }} -c "rippled -a"
- name: Setup npm version 9 - name: Setup npm version 10
run: | run: |
npm i -g npm@9 --registry=https://registry.npmjs.org npm i -g npm@10 --registry=https://registry.npmjs.org
- name: Cache node modules - name: Cache node modules
id: cache-nodemodules id: cache-nodemodules
uses: actions/cache@v3 uses: actions/cache@v4
env: env:
cache-name: cache-node-modules cache-name: cache-node-modules
with: with:
@@ -184,7 +181,6 @@ jobs:
key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: | restore-keys: |
${{ runner.os }}-deps-${{ matrix.node-version }}- ${{ runner.os }}-deps-${{ matrix.node-version }}-
${{ runner.os }}-deps-
- name: Install Dependencies - name: Install Dependencies
if: steps.cache-nodemodules.outputs.cache-hit != 'true' if: steps.cache-nodemodules.outputs.cache-hit != 'true'
@@ -205,22 +201,22 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [16.x, 18.x, 20.x] node-version: [18.x, 20.x, 22.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Setup npm version 9 - name: Setup npm version 10
run: | run: |
npm i -g npm@9 --registry=https://registry.npmjs.org npm i -g npm@10 --registry=https://registry.npmjs.org
- name: Cache node modules - name: Cache node modules
id: cache-nodemodules id: cache-nodemodules
uses: actions/cache@v3 uses: actions/cache@v4
env: env:
cache-name: cache-node-modules cache-name: cache-node-modules
with: with:
@@ -231,7 +227,6 @@ jobs:
key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: | restore-keys: |
${{ runner.os }}-deps-${{ matrix.node-version }}- ${{ runner.os }}-deps-${{ matrix.node-version }}-
${{ runner.os }}-deps-
- name: Install Dependencies - name: Install Dependencies
if: steps.cache-nodemodules.outputs.cache-hit != 'true' if: steps.cache-nodemodules.outputs.cache-hit != 'true'

View File

@@ -39,7 +39,7 @@
"enable": true "enable": true
}, },
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": true "source.fixAll.eslint": "explicit"
}, },
"files.insertFinalNewline": true, "files.insertFinalNewline": true,
"files.trimFinalNewlines": 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. 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 ## Data monitoring
- **[zerptracker](https://zerptracker.com)** - **[zerptracker](https://zerptracker.com)**

View File

@@ -12,7 +12,7 @@
### Requirements ### 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: You must also use `npm` v7. You can check your `npm` version with:
```bash ```bash
@@ -64,18 +64,20 @@ From the top-level xrpl.js folder (one level above `packages`), run the followin
```bash ```bash
npm install npm install
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up # 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-b4 /opt/ripple/bin/rippled -a --conf /opt/ripple/etc/rippled.cfg docker run -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:2.3.0-rc1 -c 'rippled -a'
npm run build npm run build
npm run test:integration npm run test:integration
``` ```
Breaking down the command: Breaking down the command:
* `docker run -p 6006:6006` starts a Docker container with an open port for admin WebSocket requests. * `docker run -p 6006:6006` starts a Docker container with an open port for admin WebSocket requests.
* `--interactive` allows you to interact with the container. `--rm` tells docker to close the container after processes are done running.
* `-t` starts a terminal in the container for you to send commands to. * `-it` allows you to interact with the container.
* `--volume $PWD/.ci-config:/config/` identifies the `rippled.cfg` and `validators.txt` to import. It must be an absolute path, so we use `$PWD` instead of `./`. `--name rippled_standalone` is an instance name for clarity
* `--volume $PWD/.ci-config:/etc/opt/ripple/` identifies the `rippled.cfg` and `validators.txt` to import. It must be an absolute path, so we use `$PWD` instead of `./`.
* `rippleci/rippled` is an image that is regularly updated with the latest `rippled` releases * `rippleci/rippled` is an image that is regularly updated with the latest `rippled` releases
* `/opt/ripple/bin/rippled -a --conf /opt/ripple/etc/rippled.cfg` starts `rippled` in standalone mode * `--entrypoint bash rippleci/rippled:2.3.0-rc1` manually overrides the entrypoint (for versions of rippled >= 2.3.0)
* `-c 'rippled -a'` provides the bash command to start `rippled` in standalone mode from the manual entrypoint
### Browser Tests ### Browser Tests
@@ -90,7 +92,7 @@ This should be run from the `xrpl.js` top level folder (one above the `packages`
```bash ```bash
npm run build npm run build
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up # 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 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:2.3.0-rc1 -c 'rippled -a'
npm run test:browser npm run test:browser
``` ```
@@ -104,6 +106,8 @@ The 4 packages currently here are:
2. ripple-binary-codec - A library for serializing and deserializing transactions for the ledger. 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. 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. 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. 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. They also run tests independently as they were originally in separate repositories.
@@ -128,13 +132,13 @@ For every file in `src`, we try to have a corresponding file in `test` with unit
The goal is to maintain above 80% code coverage, and generally any new feature or bug fix should be accompanied by unit tests, and integration tests if applicable. The goal is to maintain above 80% code coverage, and generally any new feature or bug fix should be accompanied by unit tests, and integration tests if applicable.
For an example of a unit test, check out the [autofill tests here](./packages/xrpl/test/client/autofill.ts). For an example of a unit test, check out the [autofill tests here](./packages/xrpl/test/client/autofill.test.ts).
If your code connects to the ledger (ex. Adding a new transaction type) it's handy to write integration tests to ensure that you can successfully interact with the ledger. Integration tests are generally run against a docker instance of rippled which contains the latest updates. Since standalone mode allows us to manually close ledgers, this allows us to run integration tests at a much faster rate than if we had to wait 4-5 seconds per transaction for the ledger to validate the transaction. [See above](#running-tests) for how to start up the docker container to run integration tests. If your code connects to the ledger (ex. Adding a new transaction type) it's handy to write integration tests to ensure that you can successfully interact with the ledger. Integration tests are generally run against a docker instance of rippled which contains the latest updates. Since standalone mode allows us to manually close ledgers, this allows us to run integration tests at a much faster rate than if we had to wait 4-5 seconds per transaction for the ledger to validate the transaction. [See above](#running-tests) for how to start up the docker container to run integration tests.
All integration tests should be written in the `test/integration` folder, with new `Requests` and `Transactions` tests being in their respective folders. All integration tests should be written in the `test/integration` folder, with new `Requests` and `Transactions` tests being in their respective folders.
For an example of how to write an integration test for `xrpl.js`, you can look at the [Payment integration test](./packages/xrpl/test/integration/transactions/payment.ts). For an example of how to write an integration test for `xrpl.js`, you can look at the [Payment integration test](./packages/xrpl/test/integration/transactions/payment.test.ts).
## Generate reference docs ## Generate reference docs

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. 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: This migration guide also applies to:
`ripple-address-codec` 4.3.1 -> 5.0.0 - `ripple-address-codec` 4.3.1 -> 5.0.0
`ripple-binary-codec` 1.11.0 -> 2.0.0 - `ripple-binary-codec` 1.11.0 -> 2.0.0
`ripple-keypairs` 1.3.1 -> 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? # 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' 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` ### 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)) 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)) 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 # Quickstart
### Requirements ### 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 and v22. Other versions may work but are not frequently tested.
### Installing xrpl.js ### Installing xrpl.js
@@ -56,7 +56,7 @@ async function main() {
}); });
console.log(response); console.log(response);
client.disconnect(); await client.disconnect();
} }
main(); main();
``` ```

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

View File

@@ -1,5 +1,13 @@
# @xrplf/isomorphic Release History # @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) ## 1.0.0 (2024-02-01)
Initial release providing isomorphic and tree-shakable implementations of: Initial release providing isomorphic and tree-shakable implementations of:
@@ -14,21 +22,3 @@ Initial release providing isomorphic and tree-shakable implementations of:
* randomBytes * randomBytes
* stringToHex * stringToHex
* ws * 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", "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", "description": "A collection of isomorphic and tree-shakeable crypto hashes and utils for xrpl.js",
"keywords": [ "keywords": [
"crypto", "crypto",
@@ -33,7 +33,7 @@
"ws": "^8.13.0" "ws": "^8.13.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^16.18.38", "@types/node": "^18.18.38",
"@types/ws": "^8.5.6" "@types/ws": "^8.5.6"
}, },
"repository": { "repository": {
@@ -43,6 +43,6 @@
"license": "ISC", "license": "ISC",
"prettier": "@xrplf/prettier-config", "prettier": "@xrplf/prettier-config",
"engines": { "engines": {
"node": ">=16.0.0" "node": ">=18.0.0"
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,25 +15,6 @@
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`. * Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
* Execute test in a browser in addition to node * 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) ## 4.3.1 (2023-09-27)
### Fixed ### Fixed
* Fix source-maps not finding their designated source * Fix source-maps not finding their designated source

View File

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

View File

@@ -2,6 +2,19 @@
## Unreleased ## Unreleased
## 2.2.0 (2024-12-23)
### Added
* Support for the Multi-Purpose Token amendment (XLS-33)
## 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) ## 2.0.0 (2024-02-01)
### BREAKING CHANGES ### BREAKING CHANGES
@@ -19,23 +32,6 @@
* `Comparable` is now a generic type so that it allows `compareTo` methods to take more that the type itself. * `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`. * 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 ### Changes
* Update type definitions which causing errors in tests that the code already supported * Update type definitions which causing errors in tests that the code already supported
* `makeParser` to accept a `Buffer` in addition to `string` * `makeParser` to accept a `Buffer` in addition to `string`

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -144,14 +144,18 @@ class BinaryParser {
if (type === 0) { if (type === 0) {
type = this.readUInt8() type = this.readUInt8()
if (type === 0 || type < 16) { 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) { if (nth === 0) {
nth = this.readUInt8() nth = this.readUInt8()
if (nth === 0 || nth < 16) { 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

@@ -6,6 +6,7 @@ import { JsonObject, SerializedType } from './serialized-type'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import { bytesToHex, concat, hexToBytes } from '@xrplf/isomorphic/utils' import { bytesToHex, concat, hexToBytes } from '@xrplf/isomorphic/utils'
import { readUInt32BE, writeUInt32BE } from '../utils' import { readUInt32BE, writeUInt32BE } from '../utils'
import { Hash192 } from './hash-192'
/** /**
* Constants for validating amounts * Constants for validating amounts
@@ -16,6 +17,7 @@ const MAX_IOU_PRECISION = 16
const MAX_DROPS = new BigNumber('1e17') const MAX_DROPS = new BigNumber('1e17')
const MIN_XRP = new BigNumber('1e-6') const MIN_XRP = new BigNumber('1e-6')
const mask = BigInt(0x00000000ffffffff) const mask = BigInt(0x00000000ffffffff)
const mptMask = BigInt(0x8000000000000000)
/** /**
* BigNumber configuration for Amount IOUs * BigNumber configuration for Amount IOUs
@@ -27,20 +29,28 @@ BigNumber.config({
], ],
}) })
/** interface AmountObjectIOU extends JsonObject {
* Interface for JSON objects that represent amounts
*/
interface AmountObject extends JsonObject {
value: string value: string
currency: string currency: string
issuer: string issuer: string
} }
interface AmountObjectMPT extends JsonObject {
value: string
mpt_issuance_id: string
}
/** /**
* Type guard for AmountObject * Interface for JSON objects that represent amounts
*/ */
function isAmountObject(arg): arg is AmountObject { type AmountObject = AmountObjectIOU | AmountObjectMPT
/**
* Type guard for AmountObjectIOU
*/
function isAmountObjectIOU(arg): arg is AmountObjectIOU {
const keys = Object.keys(arg).sort() const keys = Object.keys(arg).sort()
return ( return (
keys.length === 3 && keys.length === 3 &&
keys[0] === 'currency' && keys[0] === 'currency' &&
@@ -49,6 +59,17 @@ function isAmountObject(arg): arg is AmountObject {
) )
} }
/**
* Type guard for AmountObjectMPT
*/
function isAmountObjectMPT(arg): arg is AmountObjectMPT {
const keys = Object.keys(arg).sort()
return (
keys.length === 2 && keys[0] === 'mpt_issuance_id' && keys[1] === 'value'
)
}
/** /**
* Class for serializing/Deserializing Amounts * Class for serializing/Deserializing Amounts
*/ */
@@ -60,7 +81,7 @@ class Amount extends SerializedType {
} }
/** /**
* Construct an amount from an IOU or string amount * Construct an amount from an IOU, MPT or string amount
* *
* @param value An Amount, object representing an IOU, or a string * @param value An Amount, object representing an IOU, or a string
* representing an integer amount * representing an integer amount
@@ -88,7 +109,7 @@ class Amount extends SerializedType {
return new Amount(amount) return new Amount(amount)
} }
if (isAmountObject(value)) { if (isAmountObjectIOU(value)) {
const number = new BigNumber(value.value) const number = new BigNumber(value.value)
Amount.assertIouIsValid(number) Amount.assertIouIsValid(number)
@@ -124,6 +145,24 @@ class Amount extends SerializedType {
return new Amount(concat([amount, currency, issuer])) return new Amount(concat([amount, currency, issuer]))
} }
if (isAmountObjectMPT(value)) {
Amount.assertMptIsValid(value.value)
let leadingByte = new Uint8Array(1)
leadingByte[0] |= 0x60
const num = BigInt(value.value)
const intBuf = [new Uint8Array(4), new Uint8Array(4)]
writeUInt32BE(intBuf[0], Number(num >> BigInt(32)), 0)
writeUInt32BE(intBuf[1], Number(num & BigInt(mask)), 0)
amount = concat(intBuf)
const mptIssuanceID = Hash192.from(value.mpt_issuance_id).toBytes()
return new Amount(concat([leadingByte, amount, mptIssuanceID]))
}
throw new Error('Invalid type to construct an Amount') throw new Error('Invalid type to construct an Amount')
} }
@@ -134,8 +173,12 @@ class Amount extends SerializedType {
* @returns An Amount object * @returns An Amount object
*/ */
static fromParser(parser: BinaryParser): Amount { static fromParser(parser: BinaryParser): Amount {
const isXRP = parser.peek() & 0x80 const isIOU = parser.peek() & 0x80
const numBytes = isXRP ? 48 : 8 if (isIOU) return new Amount(parser.read(48))
// the amount can be either MPT or XRP at this point
const isMPT = parser.peek() & 0x20
const numBytes = isMPT ? 33 : 8
return new Amount(parser.read(numBytes)) return new Amount(parser.read(numBytes))
} }
@@ -156,7 +199,9 @@ class Amount extends SerializedType {
const num = (msb << BigInt(32)) | lsb const num = (msb << BigInt(32)) | lsb
return `${sign}${num.toString()}` return `${sign}${num.toString()}`
} else { }
if (this.isIOU()) {
const parser = new BinaryParser(this.toString()) const parser = new BinaryParser(this.toString())
const mantissa = parser.read(8) const mantissa = parser.read(8)
const currency = Currency.fromParser(parser) as Currency const currency = Currency.fromParser(parser) as Currency
@@ -182,6 +227,27 @@ class Amount extends SerializedType {
issuer: issuer.toJSON(), issuer: issuer.toJSON(),
} }
} }
if (this.isMPT()) {
const parser = new BinaryParser(this.toString())
const leadingByte = parser.read(1)
const amount = parser.read(8)
const mptID = Hash192.fromParser(parser) as Hash192
const isPositive = leadingByte[0] & 0x40
const sign = isPositive ? '' : '-'
const msb = BigInt(readUInt32BE(amount.slice(0, 4), 0))
const lsb = BigInt(readUInt32BE(amount.slice(4), 0))
const num = (msb << BigInt(32)) | lsb
return {
value: `${sign}${num.toString()}`,
mpt_issuance_id: mptID.toString(),
}
}
throw new Error('Invalid amount to construct JSON')
} }
/** /**
@@ -224,6 +290,29 @@ class Amount extends SerializedType {
} }
} }
/**
* Validate MPT.value amount
*
* @param decimal BigNumber object representing MPT.value
* @returns void, but will throw if invalid amount
*/
private static assertMptIsValid(amount: string): void {
if (amount.indexOf('.') !== -1) {
throw new Error(`${amount.toString()} is an illegal amount`)
}
const decimal = new BigNumber(amount)
if (!decimal.isZero()) {
if (decimal < BigNumber(0)) {
throw new Error(`${amount.toString()} is an illegal amount`)
}
if (Number(BigInt(amount) & BigInt(mptMask)) != 0) {
throw new Error(`${amount.toString()} is an illegal amount`)
}
}
}
/** /**
* Ensure that the value after being multiplied by the exponent does not * Ensure that the value after being multiplied by the exponent does not
* contain a decimal. * contain a decimal.
@@ -248,7 +337,25 @@ class Amount extends SerializedType {
* @returns true if Native (XRP) * @returns true if Native (XRP)
*/ */
private isNative(): boolean { private isNative(): boolean {
return (this.bytes[0] & 0x80) === 0 return (this.bytes[0] & 0x80) === 0 && (this.bytes[0] & 0x20) === 0
}
/**
* Test if this amount is in units of MPT
*
* @returns true if MPT
*/
private isMPT(): boolean {
return (this.bytes[0] & 0x80) === 0 && (this.bytes[0] & 0x20) !== 0
}
/**
* Test if this amount is in units of IOU
*
* @returns true if IOU
*/
private isIOU(): boolean {
return (this.bytes[0] & 0x80) !== 0
} }
} }

View File

@@ -33,6 +33,9 @@ class Blob extends SerializedType {
} }
if (typeof value === 'string') { 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)) return new Blob(hexToBytes(value))
} }

View File

@@ -0,0 +1,19 @@
import { Hash } from './hash'
/**
* Hash with a width of 192 bits
*/
class Hash192 extends Hash {
static readonly width = 24
static readonly ZERO_192: Hash192 = new Hash192(new Uint8Array(Hash192.width))
constructor(bytes?: Uint8Array) {
if (bytes && bytes.byteLength === 0) {
bytes = Hash192.ZERO_192.bytes
}
super(bytes ?? Hash192.ZERO_192.bytes)
}
}
export { Hash192 }

View File

@@ -4,6 +4,7 @@ import { Blob } from './blob'
import { Currency } from './currency' import { Currency } from './currency'
import { Hash128 } from './hash-128' import { Hash128 } from './hash-128'
import { Hash160 } from './hash-160' import { Hash160 } from './hash-160'
import { Hash192 } from './hash-192'
import { Hash256 } from './hash-256' import { Hash256 } from './hash-256'
import { Issue } from './issue' import { Issue } from './issue'
import { PathSet } from './path-set' import { PathSet } from './path-set'
@@ -25,6 +26,7 @@ const coreTypes: Record<string, typeof SerializedType> = {
Currency, Currency,
Hash128, Hash128,
Hash160, Hash160,
Hash192,
Hash256, Hash256,
Issue, Issue,
PathSet, PathSet,
@@ -51,6 +53,7 @@ export {
Currency, Currency,
Hash128, Hash128,
Hash160, Hash160,
Hash192,
Hash256, Hash256,
PathSet, PathSet,
STArray, STArray,

View File

@@ -67,7 +67,7 @@ class SerializedType {
* Can be customized for sidechains and amendments. * Can be customized for sidechains and amendments.
* @returns any type, if not overloaded returns hexString representation of bytes * @returns any type, if not overloaded returns hexString representation of bytes
*/ */
toJSON(_definitions?: XrplDefinitionsBase): JSON { toJSON(_definitions?: XrplDefinitionsBase, _fieldName?: string): JSON {
return this.toHex() return this.toHex()
} }

View File

@@ -14,7 +14,13 @@ const OBJECT_END_MARKER = Uint8Array.from([0xe1])
*/ */
function isObjects(args): args is Array<JsonObject> { function isObjects(args): args is Array<JsonObject> {
return ( 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

@@ -10,6 +10,7 @@ import { BinaryParser } from '../serdes/binary-parser'
import { BinarySerializer, BytesList } from '../serdes/binary-serializer' import { BinarySerializer, BytesList } from '../serdes/binary-serializer'
import { STArray } from './st-array' import { STArray } from './st-array'
import { UInt64 } from './uint-64'
const OBJECT_END_MARKER_BYTE = Uint8Array.from([0xe1]) const OBJECT_END_MARKER_BYTE = Uint8Array.from([0xe1])
const OBJECT_END_MARKER = 'ObjectEndMarker' const OBJECT_END_MARKER = 'ObjectEndMarker'
@@ -137,6 +138,8 @@ class STObject extends SerializedType {
? this.from(xAddressDecoded[field.name], undefined, definitions) ? this.from(xAddressDecoded[field.name], undefined, definitions)
: field.type.name === 'STArray' : field.type.name === 'STArray'
? STArray.from(xAddressDecoded[field.name], definitions) ? STArray.from(xAddressDecoded[field.name], definitions)
: field.type.name === 'UInt64'
? UInt64.from(xAddressDecoded[field.name], field.name)
: field.associatedType.from(xAddressDecoded[field.name]) : field.associatedType.from(xAddressDecoded[field.name])
if (associatedValue == undefined) { if (associatedValue == undefined) {
@@ -182,7 +185,7 @@ class STObject extends SerializedType {
accumulator[field.name] = objectParser accumulator[field.name] = objectParser
.readFieldValue(field) .readFieldValue(field)
.toJSON(definitions) .toJSON(definitions, field.name)
} }
return accumulator return accumulator

View File

@@ -2,10 +2,20 @@ import { UInt } from './uint'
import { BinaryParser } from '../serdes/binary-parser' import { BinaryParser } from '../serdes/binary-parser'
import { bytesToHex, concat, hexToBytes } from '@xrplf/isomorphic/utils' import { bytesToHex, concat, hexToBytes } from '@xrplf/isomorphic/utils'
import { readUInt32BE, writeUInt32BE } from '../utils' import { readUInt32BE, writeUInt32BE } from '../utils'
import { DEFAULT_DEFINITIONS, XrplDefinitionsBase } from '../enums'
const HEX_REGEX = /^[a-fA-F0-9]{1,16}$/ const HEX_REGEX = /^[a-fA-F0-9]{1,16}$/
const BASE10_REGEX = /^[0-9]{1,20}$/
const mask = BigInt(0x00000000ffffffff) const mask = BigInt(0x00000000ffffffff)
function useBase10(fieldName: string): boolean {
return (
fieldName === 'MaximumAmount' ||
fieldName === 'OutstandingAmount' ||
fieldName === 'MPTAmount'
)
}
/** /**
* Derived UInt class for serializing/deserializing 64 bit UInt * Derived UInt class for serializing/deserializing 64 bit UInt
*/ */
@@ -29,7 +39,10 @@ class UInt64 extends UInt {
* @param val A UInt64, hex-string, bigInt, or number * @param val A UInt64, hex-string, bigInt, or number
* @returns A UInt64 object * @returns A UInt64 object
*/ */
static from<T extends UInt64 | string | bigint | number>(val: T): UInt64 { static from<T extends UInt64 | string | bigint | number>(
val: T,
fieldName = '',
): UInt64 {
if (val instanceof UInt64) { if (val instanceof UInt64) {
return val return val
} }
@@ -51,11 +64,18 @@ class UInt64 extends UInt {
} }
if (typeof val === 'string') { if (typeof val === 'string') {
if (!HEX_REGEX.test(val)) { if (useBase10(fieldName)) {
if (!BASE10_REGEX.test(val)) {
throw new Error(`${fieldName} ${val} is not a valid base 10 string`)
}
val = BigInt(val).toString(16) as T
}
if (typeof val === 'string' && !HEX_REGEX.test(val)) {
throw new Error(`${val} is not a valid hex-string`) throw new Error(`${val} is not a valid hex-string`)
} }
const strBuf = val.padStart(16, '0') const strBuf = (val as string).padStart(16, '0')
buf = hexToBytes(strBuf) buf = hexToBytes(strBuf)
return new UInt64(buf) return new UInt64(buf)
} }
@@ -76,8 +96,16 @@ class UInt64 extends UInt {
* *
* @returns a hex-string * @returns a hex-string
*/ */
toJSON(): string { toJSON(
return bytesToHex(this.bytes) _definitions: XrplDefinitionsBase = DEFAULT_DEFINITIONS,
fieldName = '',
): string {
const hexString = bytesToHex(this.bytes)
if (useBase10(fieldName)) {
return BigInt('0x' + hexString).toString(10)
}
return hexString
} }
/** /**

View File

@@ -1,5 +1,7 @@
import { coreTypes } from '../src/types' import { coreTypes } from '../src/types'
import fixtures from './fixtures/data-driven-tests.json' import fixtures from './fixtures/data-driven-tests.json'
import { makeParser } from '../src/binary'
const { Amount } = coreTypes const { Amount } = coreTypes
function amountErrorTests() { function amountErrorTests() {
@@ -25,6 +27,16 @@ describe('Amount', function () {
it('can be parsed from', function () { it('can be parsed from', function () {
expect(Amount.from('1000000') instanceof Amount).toBe(true) expect(Amount.from('1000000') instanceof Amount).toBe(true)
expect(Amount.from('1000000').toJSON()).toEqual('1000000') expect(Amount.from('1000000').toJSON()).toEqual('1000000')
// it not valid to have negative XRP. But we test it anyways
// to ensure logic correctness for toJSON of the Amount class
{
const parser = makeParser('0000000000000001')
const value = parser.readType(Amount)
const json = value.toJSON()
expect(json).toEqual('-1')
}
const fixture = { const fixture = {
value: '1', value: '1',
issuer: '0000000000000000000000000000000000000000', issuer: '0000000000000000000000000000000000000000',
@@ -38,5 +50,35 @@ describe('Amount', function () {
} }
expect(amt.toJSON()).toEqual(rewritten) expect(amt.toJSON()).toEqual(rewritten)
}) })
it('can be parsed from MPT', function () {
let fixture = {
value: '100',
mpt_issuance_id: '00002403C84A0A28E0190E208E982C352BBD5006600555CF',
}
let amt = Amount.from(fixture)
expect(amt.toJSON()).toEqual(fixture)
fixture = {
value: '9223372036854775807',
mpt_issuance_id: '00002403C84A0A28E0190E208E982C352BBD5006600555CF',
}
amt = Amount.from(fixture)
expect(amt.toJSON()).toEqual(fixture)
// it not valid to have negative MPT. But we test it anyways
// to ensure logic correctness for toJSON of the Amount class
{
const parser = makeParser(
'20000000000000006400002403C84A0A28E0190E208E982C352BBD5006600555CF',
)
const value = parser.readType(Amount)
const json = value.toJSON()
expect(json).toEqual({
mpt_issuance_id: '00002403C84A0A28E0190E208E982C352BBD5006600555CF',
value: '-100',
})
}
})
amountErrorTests() amountErrorTests()
}) })

View File

@@ -22,6 +22,7 @@ function assertEqualAmountJSON(actual, expected) {
} }
expect(actual.currency).toEqual(expected.currency) expect(actual.currency).toEqual(expected.currency)
expect(actual.issuer).toEqual(expected.issuer) expect(actual.issuer).toEqual(expected.issuer)
expect(actual.mpt_issuance_id).toEqual(expected.mpt_issuance_id)
expect( expect(
actual.value === expected.value || actual.value === expected.value ||
new BigNumber(actual.value).eq(new BigNumber(expected.value)), new BigNumber(actual.value).eq(new BigNumber(expected.value)),
@@ -207,12 +208,12 @@ function amountParsingTests() {
return return
} }
const parser = makeParser(f.expected_hex) const parser = makeParser(f.expected_hex)
const testName = `values_tests[${i}] parses ${f.expected_hex.slice( const hexToJsonTestName = `values_tests[${i}] parses ${f.expected_hex.slice(
0, 0,
16, 16,
)}... )}...
as ${JSON.stringify(f.test_json)}` as ${JSON.stringify(f.test_json)}`
it(testName, () => { it(hexToJsonTestName, () => {
const value = parser.readType(Amount) const value = parser.readType(Amount)
// May not actually be in canonical form. The fixtures are to be used // May not actually be in canonical form. The fixtures are to be used
// also for json -> binary; // also for json -> binary;
@@ -223,6 +224,15 @@ function amountParsingTests() {
expect((exponent.e ?? 0) - 15).toEqual(f?.exponent) expect((exponent.e ?? 0) - 15).toEqual(f?.exponent)
} }
}) })
const jsonToHexTestName = `values_tests[${i}] parses ${JSON.stringify(
f.test_json,
)}...
as ${f.expected_hex.slice(0, 16)}`
it(jsonToHexTestName, () => {
const amt = Amount.from(f.test_json)
expect(amt.toHex()).toEqual(f.expected_hex)
})
}) })
} }
@@ -238,19 +248,19 @@ function fieldParsingTests() {
it('Field throws when type code out of range', () => { it('Field throws when type code out of range', () => {
const parser = makeParser('0101') const parser = makeParser('0101')
expect(() => parser.readField()).toThrow( 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', () => { it('Field throws when field code out of range', () => {
const parser = makeParser('1001') const parser = makeParser('1001')
expect(() => parser.readFieldOrdinal()).toThrow( 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', () => { it('Field throws when both type and field code out of range', () => {
const parser = makeParser('000101') const parser = makeParser('000101')
expect(() => parser.readFieldOrdinal()).toThrow( 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', () => { it('readUIntN', () => {

View File

@@ -4868,6 +4868,36 @@
"TxnSignature": "AACD31A04CAE14670FC483A1382F393AA96B49C84479B58067F049FBD772999325667A6AA2520A63756EE84F3657298815019DD56A1AECE796B08535C4009C08", "TxnSignature": "AACD31A04CAE14670FC483A1382F393AA96B49C84479B58067F049FBD772999325667A6AA2520A63756EE84F3657298815019DD56A1AECE796B08535C4009C08",
"URI": "6469645F6578616D706C65" "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": [{ "ledgerData": [{

View File

@@ -2499,7 +2499,7 @@
"type_id": 6, "type_id": 6,
"is_native": true, "is_native": true,
"type": "Amount", "type": "Amount",
"expected_hex": "0000000000000001", "error": "Value is negative",
"is_negative": true "is_negative": true
}, },
{ {
@@ -2914,6 +2914,170 @@
"type": "Amount", "type": "Amount",
"error": "10000000000000000000 absolute XRP is bigger than max native value 100000000000.0", "error": "10000000000000000000 absolute XRP is bigger than max native value 100000000000.0",
"is_negative": true "is_negative": true
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "9223372036854775808"
},
"type": "Amount",
"error": "Value is too large"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "18446744073709551615"
},
"type": "Amount",
"error": "Value is too large"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "-1"
},
"type": "Amount",
"error": "Value is negative"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "10.1"
},
"type": "Amount",
"error": "Value has decimal point"
},
{
"test_json": {
"mpt_issuance_id": "10",
"value": "10"
},
"type": "Amount",
"error": "mpt_issuance_id has invalid hash length"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "10",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji"
},
"type": "Amount",
"error": "Issuer not valid for MPT"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "10",
"currency": "USD"
},
"type": "Amount",
"error": "Currency not valid for MPT"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "a"
},
"type": "Amount",
"error": "Value has incorrect hex format"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0xy"
},
"type": "Amount",
"error": "Value has bad hex character"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "/"
},
"type": "Amount",
"error": "Value has bad character"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0x8000000000000000"
},
"type": "Amount",
"error": "Hex value out of range"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0xFFFFFFFFFFFFFFFF"
},
"type": "Amount",
"error": "Hex value out of range"
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "9223372036854775807"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "607FFFFFFFFFFFFFFF00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "60000000000000000000002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "-0"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "60000000000000000000002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "100"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "60000000000000006400002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0xa"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "60000000000000000A00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0x7FFFFFFFFFFFFFFF"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "607FFFFFFFFFFFFFFF00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
} }
] ]
} }

View File

@@ -1,4 +1,11 @@
import { Hash128, Hash160, Hash256, AccountID, Currency } from '../src/types' import {
Hash128,
Hash160,
Hash192,
Hash256,
AccountID,
Currency,
} from '../src/types'
describe('Hash128', function () { describe('Hash128', function () {
it('has a static width member', function () { it('has a static width member', function () {
@@ -51,6 +58,33 @@ describe('Hash160', function () {
}) })
}) })
describe('Hash192', function () {
it('has a static width member', function () {
expect(Hash192.width).toBe(24)
})
it('has a ZERO_192 member', function () {
expect(Hash192.ZERO_192.toJSON()).toBe(
'000000000000000000000000000000000000000000000000',
)
})
it('can be compared against another', function () {
const h1 = Hash192.from('100000000000000000000000000000000000000000000000')
const h2 = Hash192.from('200000000000000000000000000000000000000000000000')
const h3 = Hash192.from('000000000000000000000000000000000000000000000003')
expect(h1.lt(h2)).toBe(true)
expect(h3.lt(h2)).toBe(true)
})
it('throws when constructed from invalid hash length', () => {
expect(() =>
Hash192.from('10000000000000000000000000000000000000000000000'),
).toThrow(new Error('Invalid Hash length 23'))
expect(() =>
Hash192.from('10000000000000000000000000000000000000000000000000'),
).toThrow(new Error('Invalid Hash length 25'))
})
})
describe('Hash256', function () { describe('Hash256', function () {
it('has a static width member', function () { it('has a static width member', function () {
expect(Hash256.width).toBe(32) expect(Hash256.width).toBe(32)

View File

@@ -73,7 +73,9 @@ describe('Signing data', function () {
const customPaymentDefinitions = JSON.parse( const customPaymentDefinitions = JSON.parse(
JSON.stringify(normalDefinitions), JSON.stringify(normalDefinitions),
) )
customPaymentDefinitions.TRANSACTION_TYPES.Payment = 31
// custom number would need to updated in case it has been used by an existing transaction type
customPaymentDefinitions.TRANSACTION_TYPES.Payment = 200
const newDefs = new XrplDefinitions(customPaymentDefinitions) const newDefs = new XrplDefinitions(customPaymentDefinitions)
const actual = encodeForSigning(tx_json, newDefs) const actual = encodeForSigning(tx_json, newDefs)
@@ -82,7 +84,7 @@ describe('Signing data', function () {
'53545800', // signingPrefix '53545800', // signingPrefix
// TransactionType // TransactionType
'12', '12',
'001F', '00C8',
// Flags // Flags
'22', '22',
'80000000', '80000000',
@@ -176,7 +178,9 @@ describe('Signing data', function () {
const customPaymentDefinitions = JSON.parse( const customPaymentDefinitions = JSON.parse(
JSON.stringify(normalDefinitions), JSON.stringify(normalDefinitions),
) )
customPaymentDefinitions.TRANSACTION_TYPES.Payment = 31
// custom number would need to updated in case it has been used by an existing transaction type
customPaymentDefinitions.TRANSACTION_TYPES.Payment = 200
const newDefs = new XrplDefinitions(customPaymentDefinitions) const newDefs = new XrplDefinitions(customPaymentDefinitions)
const signingAccount = 'rJZdUusLDtY9NEsGea7ijqhVrXv98rYBYN' const signingAccount = 'rJZdUusLDtY9NEsGea7ijqhVrXv98rYBYN'
@@ -187,7 +191,7 @@ describe('Signing data', function () {
'534D5400', // signingPrefix '534D5400', // signingPrefix
// TransactionType // TransactionType
'12', '12',
'001F', '00C8',
// Flags // Flags
'22', '22',
'80000000', '80000000',

View File

@@ -1,5 +1,5 @@
import { UInt8, UInt64 } from '../src/types' import { UInt8, UInt64 } from '../src/types'
import { encode } from '../src' import { encode, decode } from '../src'
const binary = const binary =
'11007222000300003700000000000000003800000000000000006280000000000000000000000000000000000000005553440000000000000000000000000000000000000000000000000166D5438D7EA4C680000000000000000000000000005553440000000000AE123A8556F3CF91154711376AFB0F894F832B3D67D5438D7EA4C680000000000000000000000000005553440000000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B90F' '11007222000300003700000000000000003800000000000000006280000000000000000000000000000000000000005553440000000000000000000000000000000000000000000000000166D5438D7EA4C680000000000000000000000000005553440000000000AE123A8556F3CF91154711376AFB0F894F832B3D67D5438D7EA4C680000000000000000000000000005553440000000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B90F'
@@ -96,6 +96,40 @@ const jsonEntry2 = {
index: '0000041EFD027808D3F78C8352F97E324CB816318E00B977C74ECDDC7CD975B2', index: '0000041EFD027808D3F78C8352F97E324CB816318E00B977C74ECDDC7CD975B2',
} }
const mptIssuanceEntryBinary =
'11007E220000006224000002DF25000002E434000000000000000030187FFFFFFFFFFFFFFF30190000000000000064552E78C1FFBDDAEE077253CEB12CFEA83689AA0899F94762190A357208DADC76FE701EC1EC7B226E616D65223A2255532054726561737572792042696C6C20546F6B656E222C2273796D626F6C223A225553544254222C22646563696D616C73223A322C22746F74616C537570706C79223A313030303030302C22697373756572223A225553205472656173757279222C22697373756544617465223A22323032342D30332D3235222C226D6174757269747944617465223A22323032352D30332D3235222C226661636556616C7565223A2231303030222C22696E74657265737452617465223A22322E35222C22696E7465726573744672657175656E6379223A22517561727465726C79222C22636F6C6C61746572616C223A22555320476F7665726E6D656E74222C226A7572697364696374696F6E223A22556E6974656420537461746573222C22726567756C61746F7279436F6D706C69616E6365223A2253454320526567756C6174696F6E73222C22736563757269747954797065223A2254726561737572792042696C6C222C2265787465726E616C5F75726C223A2268747470733A2F2F6578616D706C652E636F6D2F742D62696C6C2D746F6B656E2D6D657461646174612E6A736F6E227D8414A4D893CFBC4DC6AE877EB585F90A3B47528B958D051003'
const mptIssuanceEntryJson = {
AssetScale: 3,
Flags: 98,
Issuer: 'rGpdGXDV2RFPeLEfWS9RFo5Nh9cpVDToZa',
LedgerEntryType: 'MPTokenIssuance',
MPTokenMetadata:
'7B226E616D65223A2255532054726561737572792042696C6C20546F6B656E222C2273796D626F6C223A225553544254222C22646563696D616C73223A322C22746F74616C537570706C79223A313030303030302C22697373756572223A225553205472656173757279222C22697373756544617465223A22323032342D30332D3235222C226D6174757269747944617465223A22323032352D30332D3235222C226661636556616C7565223A2231303030222C22696E74657265737452617465223A22322E35222C22696E7465726573744672657175656E6379223A22517561727465726C79222C22636F6C6C61746572616C223A22555320476F7665726E6D656E74222C226A7572697364696374696F6E223A22556E6974656420537461746573222C22726567756C61746F7279436F6D706C69616E6365223A2253454320526567756C6174696F6E73222C22736563757269747954797065223A2254726561737572792042696C6C222C2265787465726E616C5F75726C223A2268747470733A2F2F6578616D706C652E636F6D2F742D62696C6C2D746F6B656E2D6D657461646174612E6A736F6E227D',
MaximumAmount: '9223372036854775807',
OutstandingAmount: '100',
OwnerNode: '0000000000000000',
PreviousTxnID:
'2E78C1FFBDDAEE077253CEB12CFEA83689AA0899F94762190A357208DADC76FE',
PreviousTxnLgrSeq: 740,
Sequence: 735,
}
const mptokenEntryJson = {
Account: 'raDQsd1s8rqGjL476g59a9vVNi1rSwrC44',
Flags: 0,
LedgerEntryType: 'MPToken',
MPTAmount: '100',
MPTokenIssuanceID: '000002DF71CAE59C9B7E56587FFF74D4EA5830D9BE3CE0CC',
OwnerNode: '0000000000000000',
PreviousTxnID:
'222EF3C7E82D8A44984A66E2B8E357CB536EC2547359CCF70E56E14BC4C284C8',
PreviousTxnLgrSeq: 741,
}
const mptokenEntryBinary =
'11007F220000000025000002E5340000000000000000301A000000000000006455222EF3C7E82D8A44984A66E2B8E357CB536EC2547359CCF70E56E14BC4C284C881143930DB9A74C26D96CB58ADFFD7E8BB78BCFE62340115000002DF71CAE59C9B7E56587FFF74D4EA5830D9BE3CE0CC'
it('compareToTests[0]', () => { it('compareToTests[0]', () => {
expect(UInt8.from(124).compareTo(UInt64.from(124))).toBe(0) expect(UInt8.from(124).compareTo(UInt64.from(124))).toBe(0)
}) })
@@ -144,3 +178,20 @@ it('valueOf tests', () => {
expect(val.valueOf() | 0x2).toBe(3) expect(val.valueOf() | 0x2).toBe(3)
}) })
it('UInt64 is parsed as base 10 for MPT amounts', () => {
expect(encode(mptIssuanceEntryJson)).toEqual(mptIssuanceEntryBinary)
expect(decode(mptIssuanceEntryBinary)).toEqual(mptIssuanceEntryJson)
expect(encode(mptokenEntryJson)).toEqual(mptokenEntryBinary)
expect(decode(mptokenEntryBinary)).toEqual(mptokenEntryJson)
const decodedIssuance = decode(mptIssuanceEntryBinary)
expect(typeof decodedIssuance.MaximumAmount).toBe('string')
expect(decodedIssuance.MaximumAmount).toBe('9223372036854775807')
expect(decodedIssuance.OutstandingAmount).toBe('100')
const decodedToken = decode(mptokenEntryBinary)
expect(typeof decodedToken.MPTAmount).toBe('string')
expect(decodedToken.MPTAmount).toBe('100')
})

View File

@@ -19,29 +19,6 @@
* Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead. * Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead.
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`. * 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) ## 1.3.1 (2023-09-27)
### Fixed ### Fixed
* Fix source-maps not finding their designated source * Fix source-maps not finding their designated source

View File

@@ -36,6 +36,6 @@
"license": "ISC", "license": "ISC",
"prettier": "@xrplf/prettier-config", "prettier": "@xrplf/prettier-config",
"engines": { "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. * Unit tests run in a browser and node.
* Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead. * Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead.
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`. * 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,11 +2,57 @@
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. 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 ## Unreleased Changes
## 4.1.0 (2024-12-23)
### Added
* Added new MPT transaction definitions (XLS-33)
* New `MPTAmount` type support for `Payment` and `Clawback` transactions
* `parseTransactionFlags` as a utility function in the xrpl package to streamline transactions flags-to-map conversion
* Support for XLS-70d (Credentials)
### Fixed
* `TransactionStream` model supports APIv2
* `TransactionStream` model includes `close_time_iso` field
* `Ledger` model includes `close_time_iso` field
## 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
* Add `include_deleted` to ledgerEntry request and `deleted_ledger_index` to ledgerEntry response
* 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) ## 3.0.0 (2024-02-01)
### BREAKING CHANGES ### BREAKING CHANGES
* The default signing algorithm in the `Wallet` was changed from secp256k1 to ed25519
* Bump typescript to 5.x * Bump typescript to 5.x
* Remove Node 14 support * 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 `crypto` polyfills, `create-hash`, `elliptic`, `hash.js`, and their many dependencies in favor of `@noble/hashes` and `@nobel/curves`
@@ -52,80 +98,6 @@ Bundler configurations are much more simplified. See [../UNIQUE_STEPS](Unique St
* Deprecated: * Deprecated:
* `convertHexToString` in favor of `@xrplf/isomorphic/utils`'s `hexToString` * `convertHexToString` in favor of `@xrplf/isomorphic/utils`'s `hexToString`
* `convertStringToHex` in favor of `@xrplf/isomorphic/utils`'s `stringToHex` * `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) ## 2.14.1 (2024-02-01)

View File

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

View File

@@ -1,170 +0,0 @@
/* eslint-disable max-depth -- needed for attestation checking */
/* eslint-disable @typescript-eslint/consistent-type-assertions -- needed here */
/* eslint-disable no-await-in-loop -- needed here */
import {
AccountObjectsRequest,
LedgerEntry,
Client,
XChainAccountCreateCommit,
XChainBridge,
XChainCommit,
XChainCreateClaimID,
xrpToDrops,
Wallet,
getXChainClaimID,
} from '../../src'
async function sleep(sec: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, sec * 1000)
})
}
const lockingClient = new Client('wss://s.devnet.rippletest.net:51233')
const issuingClient = new Client(
'wss://sidechain-net2.devnet.rippletest.net:51233',
)
const MAX_LEDGERS_WAITED = 5
const LEDGER_CLOSE_TIME = 4
void bridgeTransfer()
async function bridgeTransfer(): Promise<void> {
await lockingClient.connect()
await issuingClient.connect()
const lockingChainDoor = 'rnQAXXWoFNN6PEqwqsdTngCtFPCrmfuqFJ'
const accountObjectsRequest: AccountObjectsRequest = {
command: 'account_objects',
account: lockingChainDoor,
type: 'bridge',
}
const lockingAccountObjects = (
await lockingClient.request(accountObjectsRequest)
).result.account_objects
// There will only be one here - a door account can only have one bridge per currency
const bridgeData = lockingAccountObjects.filter(
(obj) =>
obj.LedgerEntryType === 'Bridge' &&
obj.XChainBridge.LockingChainIssue.currency === 'XRP',
)[0] as LedgerEntry.Bridge
const bridge: XChainBridge = bridgeData.XChainBridge
console.log(bridge)
console.log('Creating wallet on the locking chain via the faucet...')
const { wallet: wallet1 } = await lockingClient.fundWallet()
console.log(wallet1)
const wallet2 = Wallet.generate()
console.log(
`Creating ${wallet2.classicAddress} on the issuing chain via the bridge...`,
)
const fundTx: XChainAccountCreateCommit = {
TransactionType: 'XChainAccountCreateCommit',
Account: wallet1.classicAddress,
XChainBridge: bridge,
SignatureReward: bridgeData.SignatureReward,
Destination: wallet2.classicAddress,
Amount: (
parseInt(bridgeData.MinAccountCreateAmount as string, 10) * 2
).toString(),
}
const fundResponse = await lockingClient.submitAndWait(fundTx, {
wallet: wallet1,
})
console.log(fundResponse)
console.log(
'Waiting for the attestation to go through... (usually 8-12 seconds)',
)
let ledgersWaited = 0
let initialBalance = 0
while (ledgersWaited < MAX_LEDGERS_WAITED) {
await sleep(LEDGER_CLOSE_TIME)
try {
initialBalance = await issuingClient.getXrpBalance(wallet2.classicAddress)
console.log(
`Wallet ${wallet2.classicAddress} has been funded with a balance of ${initialBalance} XRP`,
)
break
} catch (_error) {
ledgersWaited += 1
if (ledgersWaited === MAX_LEDGERS_WAITED) {
// This error should never be hit if the bridge is running
throw Error('Destination account creation via the bridge failed.')
}
}
}
console.log(
`Transferring funds from ${wallet1.classicAddress} on the locking chain to ` +
`${wallet2.classicAddress} on the issuing_chain...`,
)
// Fetch the claim ID for the transfer
console.log('Step 1: Fetching the claim ID for the transfer...')
const claimIdTx: XChainCreateClaimID = {
TransactionType: 'XChainCreateClaimID',
Account: wallet2.classicAddress,
XChainBridge: bridge,
SignatureReward: bridgeData.SignatureReward,
OtherChainSource: wallet1.classicAddress,
}
const claimIdResult = await issuingClient.submitAndWait(claimIdTx, {
wallet: wallet2,
})
console.log(claimIdResult)
// Extract new claim ID from metadata
const xchainClaimId = getXChainClaimID(claimIdResult.result.meta)
if (xchainClaimId == null) {
// This shouldn't trigger assuming the transaction succeeded
throw Error('Could not extract XChainClaimID')
}
console.log(`Claim ID for the transfer: ${xchainClaimId}`)
console.log(
'Step 2: Locking the funds on the locking chain with an XChainCommit transaction...',
)
const commitTx: XChainCommit = {
TransactionType: 'XChainCommit',
Account: wallet1.classicAddress,
Amount: xrpToDrops(1),
XChainBridge: bridge,
XChainClaimID: xchainClaimId,
OtherChainDestination: wallet2.classicAddress,
}
const commitResult = await lockingClient.submitAndWait(commitTx, {
wallet: wallet1,
})
console.log(commitResult)
console.log(
'Waiting for the attestation to go through... (usually 8-12 seconds)',
)
ledgersWaited = 0
while (ledgersWaited < MAX_LEDGERS_WAITED) {
await sleep(LEDGER_CLOSE_TIME)
const currentBalance = await issuingClient.getXrpBalance(
wallet2.classicAddress,
)
console.log(initialBalance, currentBalance)
if (currentBalance > initialBalance) {
console.log('Transfer is complete')
console.log(
`New balance of ${wallet2.classicAddress} is ${currentBalance} XRP`,
)
break
}
ledgersWaited += 1
if (ledgersWaited === MAX_LEDGERS_WAITED) {
throw Error('Bridge transfer failed.')
}
}
await lockingClient.disconnect()
await issuingClient.disconnect()
}

View File

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

View File

@@ -1,5 +1,11 @@
import { Client, Payment } from '../../src' import { Client, Payment } from '../../src'
// Prerequisites for this snippet. Please verify these conditions after a reset of the
// test network:
// - destination_account must have a trust line with the destination_amount.issuer
// - There must be appropriate DEX Offers or XRP/TST AMM for the cross-currency exchange
// PathFind RPC requires the use of a Websocket client only
const client = new Client('wss://s.altnet.rippletest.net:51233') const client = new Client('wss://s.altnet.rippletest.net:51233')
async function createTxWithPaths(): Promise<void> { async function createTxWithPaths(): Promise<void> {
@@ -8,22 +14,17 @@ async function createTxWithPaths(): Promise<void> {
const { wallet } = await client.fundWallet(null, { const { wallet } = await client.fundWallet(null, {
usageContext: 'code snippets', usageContext: 'code snippets',
}) })
const destination_account = 'rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj' const destination_account = 'rJPeZVPty1bXXbDR9oKscg2irqABr7sP3t'
const destination_amount = { const destination_amount = {
value: '0.001', value: '0.001',
currency: 'USD', currency: 'TST',
issuer: 'rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc', issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
} }
const resp = await client.request({ const resp = await client.request({
// TOOD: Replace with path_find - https://github.com/XRPLF/xrpl.js/issues/2385 command: 'path_find',
command: 'ripple_path_find', subcommand: 'create',
source_account: wallet.classicAddress, source_account: wallet.classicAddress,
source_currencies: [
{
currency: 'XRP',
},
],
destination_account, destination_account,
destination_amount, destination_amount,
}) })

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,12 @@ import {
ValidationError, ValidationError,
XrplError, XrplError,
} from '../errors' } from '../errors'
import type { LedgerIndex, Balance } from '../models/common' import {
APIVersion,
LedgerIndex,
Balance,
DEFAULT_API_VERSION,
} from '../models/common'
import { import {
Request, Request,
// account methods // account methods
@@ -88,8 +93,23 @@ import {
} from './partialPayment' } from './partialPayment'
export interface ClientOptions extends ConnectionUserOptions { 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 feeCushion?: number
/**
* Maximum transaction cost to allow, in decimal XRP. Must be a string-encoded
* number. Defaults to '2'.
*
* @category Fee
*/
maxFeeXRP?: string maxFeeXRP?: string
/**
* Duration to wait for a request to timeout.
*/
timeout?: number timeout?: number
} }
@@ -198,6 +218,12 @@ class Client extends EventEmitter<EventTypes> {
*/ */
public buildVersion: string | undefined 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. * 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') * 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 = {}) { public constructor(server: string, options: ClientOptions = {}) {
super() super()
if (typeof server !== 'string' || !/wss?(?:\+unix)?:\/\//u.exec(server)) { if (typeof server !== 'string' || !/wss?(?:\+unix)?:\/\//u.exec(server)) {
@@ -275,6 +301,7 @@ class Client extends EventEmitter<EventTypes> {
this.emit('path_find', path) this.emit('path_find', path)
}) })
} }
/* eslint-enable max-lines-per-function */
/** /**
* Get the url that the client is connected to. * Get the url that the client is connected to.
@@ -291,7 +318,6 @@ class Client extends EventEmitter<EventTypes> {
* additional request body parameters. * additional request body parameters.
* *
* @category Network * @category Network
*
* @param req - Request to send to the server. * @param req - Request to send to the server.
* @returns The response from the server. * @returns The response from the server.
* *
@@ -304,16 +330,20 @@ class Client extends EventEmitter<EventTypes> {
* console.log(response) * console.log(response)
* ``` * ```
*/ */
public async request<R extends Request, T = RequestResponseMap<R>>( public async request<
req: R, R extends Request,
): Promise<T> { V extends APIVersion = typeof DEFAULT_API_VERSION,
const response = await this.connection.request<R, T>({ T = RequestResponseMap<R, V>,
>(req: R): Promise<T> {
const request = {
...req, ...req,
account: req.account account:
? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Must be string typeof req.account === 'string'
ensureClassicAddress(req.account as string) ? ensureClassicAddress(req.account)
: undefined, : undefined,
}) api_version: req.api_version ?? this.apiVersion,
}
const response = await this.connection.request<R, T>(request)
// mutates `response` to add warnings // mutates `response` to add warnings
handlePartialPayment(req.command, response) handlePartialPayment(req.command, response)
@@ -422,9 +452,10 @@ class Client extends EventEmitter<EventTypes> {
* const allResponses = await client.requestAll({ command: 'transaction_data' }); * const allResponses = await client.requestAll({ command: 'transaction_data' });
* console.log(allResponses); * console.log(allResponses);
*/ */
public async requestAll< public async requestAll<
T extends MarkerRequest, T extends MarkerRequest,
U = RequestAllResponseMap<T>, U = RequestAllResponseMap<T, APIVersion>,
>(request: T, collect?: string): Promise<U[]> { >(request: T, collect?: string): Promise<U[]> {
/* /*
* The data under collection is keyed based on the command. Fail if command * The data under collection is keyed based on the command. Fail if command
@@ -441,7 +472,6 @@ class Client extends EventEmitter<EventTypes> {
const countTo: number = request.limit == null ? Infinity : request.limit const countTo: number = request.limit == null ? Infinity : request.limit
let count = 0 let count = 0
let marker: unknown = request.marker let marker: unknown = request.marker
let lastBatchLength: number
const results: U[] = [] const results: U[] = []
do { do {
const countRemaining = clamp(countTo - count, MIN_LIMIT, MAX_LIMIT) 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 // eslint-disable-next-line no-await-in-loop -- Necessary for this, it really has to wait
const singleResponse = await this.connection.request(repeatProps) const singleResponse = await this.connection.request(repeatProps)
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Should be true // 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)) { if (!(collectKey in singleResult)) {
throw new XrplError(`${collectKey} not in result`) 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. // Make sure we handle when no data (not even an empty array) is returned.
if (Array.isArray(collectedData)) { if (Array.isArray(collectedData)) {
count += collectedData.length count += collectedData.length
lastBatchLength = collectedData.length
} else {
lastBatchLength = 0
} }
} while (Boolean(marker) && count < countTo && lastBatchLength !== 0) } while (Boolean(marker) && count < countTo)
return results return results
} }
@@ -627,7 +654,10 @@ class Client extends EventEmitter<EventTypes> {
* @param signersCount - The expected number of signers for this transaction. * @param signersCount - The expected number of signers for this transaction.
* Only used for multisigned transactions. * Only used for multisigned transactions.
* @returns The autofilled transaction. * @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>( public async autofill<T extends SubmittableTransaction>(
transaction: T, transaction: T,
signersCount?: number, signersCount?: number,
@@ -635,7 +665,6 @@ class Client extends EventEmitter<EventTypes> {
const tx = { ...transaction } const tx = { ...transaction }
setValidAddresses(tx) setValidAddresses(tx)
setTransactionFlagsToNumber(tx) setTransactionFlagsToNumber(tx)
const promises: Array<Promise<void>> = [] const promises: Array<Promise<void>> = []
@@ -655,6 +684,34 @@ class Client extends EventEmitter<EventTypes> {
promises.push(checkAccountDeleteBlockers(this, tx)) 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) return Promise.all(promises).then(() => tx)
} }
@@ -898,7 +955,7 @@ class Client extends EventEmitter<EventTypes> {
* @param options.limit - Limit number of balances to return. * @param options.limit - Limit number of balances to return.
* @returns An array of XRP/non-XRP balances for the given account. * @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( public async getBalances(
address: string, address: string,
options: { options: {
@@ -946,6 +1003,7 @@ class Client extends EventEmitter<EventTypes> {
) )
return balances.slice(0, options.limit) 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 * Fetch orderbook (buy/sell orders) between two currency pairs. This checks both sides of the orderbook

View File

@@ -2,21 +2,37 @@ import BigNumber from 'bignumber.js'
import { decode } from 'ripple-binary-codec' import { decode } from 'ripple-binary-codec'
import type { import type {
AccountTxResponse,
TransactionEntryResponse, TransactionEntryResponse,
TransactionStream, TransactionStream,
TransactionV1Stream,
TxResponse, TxResponse,
} from '..' } from '..'
import type { Amount } from '../models/common' import type {
import type { RequestResponseMap } from '../models/methods' Amount,
IssuedCurrency,
APIVersion,
DEFAULT_API_VERSION,
MPTAmount,
} from '../models/common'
import type {
AccountTxTransaction,
RequestResponseMap,
} from '../models/methods'
import { AccountTxVersionResponseMap } from '../models/methods/accountTx'
import { BaseRequest, BaseResponse } from '../models/methods/baseMethod' import { BaseRequest, BaseResponse } from '../models/methods/baseMethod'
import { PaymentFlags, Transaction } from '../models/transactions' import { PaymentFlags, Transaction, isMPTAmount } from '../models/transactions'
import type { TransactionMetadata } from '../models/transactions/metadata' import type { TransactionMetadata } from '../models/transactions/metadata'
import { isFlagEnabled } from '../models/utils' import { isFlagEnabled } from '../models/utils'
const WARN_PARTIAL_PAYMENT_CODE = 2001 const WARN_PARTIAL_PAYMENT_CODE = 2001
function amountsEqual(amt1: Amount, amt2: Amount): boolean { /* eslint-disable complexity -- check different token types */
/* eslint-disable @typescript-eslint/consistent-type-assertions -- known currency type */
function amountsEqual(
amt1: Amount | MPTAmount,
amt2: Amount | MPTAmount,
): boolean {
// Compare XRP
if (typeof amt1 === 'string' && typeof amt2 === 'string') { if (typeof amt1 === 'string' && typeof amt2 === 'string') {
return amt1 === amt2 return amt1 === amt2
} }
@@ -25,15 +41,32 @@ function amountsEqual(amt1: Amount, amt2: Amount): boolean {
return false return false
} }
// Compare MPTs
if (isMPTAmount(amt1) && isMPTAmount(amt2)) {
const aValue = new BigNumber(amt1.value)
const bValue = new BigNumber(amt2.value)
return (
amt1.mpt_issuance_id === amt2.mpt_issuance_id && aValue.isEqualTo(bValue)
)
}
if (isMPTAmount(amt1) || isMPTAmount(amt2)) {
return false
}
// Compare issued currency (IOU)
const aValue = new BigNumber(amt1.value) const aValue = new BigNumber(amt1.value)
const bValue = new BigNumber(amt2.value) const bValue = new BigNumber(amt2.value)
return ( return (
amt1.currency === amt2.currency && (amt1 as IssuedCurrency).currency === (amt2 as IssuedCurrency).currency &&
amt1.issuer === amt2.issuer && (amt1 as IssuedCurrency).issuer === (amt2 as IssuedCurrency).issuer &&
aValue.isEqualTo(bValue) aValue.isEqualTo(bValue)
) )
} }
/* eslint-enable complexity */
/* eslint-enable @typescript-eslint/consistent-type-assertions */
function isPartialPayment( function isPartialPayment(
tx?: Transaction, tx?: Transaction,
@@ -63,7 +96,10 @@ function isPartialPayment(
} }
const delivered = meta.delivered_amount 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) { if (delivered === undefined) {
return false return false
@@ -73,23 +109,36 @@ function isPartialPayment(
} }
function txHasPartialPayment(response: TxResponse): boolean { 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 { function txEntryHasPartialPayment(response: TransactionEntryResponse): boolean {
return isPartialPayment(response.result.tx_json, response.result.metadata) 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 { 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 return foo
} }
function hasPartialPayment<R extends BaseRequest, T = RequestResponseMap<R>>( function hasPartialPayment<
command: string, R extends BaseRequest,
response: T, V extends APIVersion = typeof DEFAULT_API_VERSION,
): boolean { T = RequestResponseMap<R, V>,
>(command: string, response: T): boolean {
/* eslint-disable @typescript-eslint/consistent-type-assertions -- Request type is known at runtime from command */ /* eslint-disable @typescript-eslint/consistent-type-assertions -- Request type is known at runtime from command */
switch (command) { switch (command) {
case 'tx': case 'tx':
@@ -97,7 +146,9 @@ function hasPartialPayment<R extends BaseRequest, T = RequestResponseMap<R>>(
case 'transaction_entry': case 'transaction_entry':
return txEntryHasPartialPayment(response as TransactionEntryResponse) return txEntryHasPartialPayment(response as TransactionEntryResponse)
case 'account_tx': case 'account_tx':
return accountTxHasPartialPayment(response as AccountTxResponse) return accountTxHasPartialPayment(
response as AccountTxVersionResponseMap<V>,
)
default: default:
return false return false
} }
@@ -112,7 +163,7 @@ function hasPartialPayment<R extends BaseRequest, T = RequestResponseMap<R>>(
*/ */
export function handlePartialPayment< export function handlePartialPayment<
R extends BaseRequest, R extends BaseRequest,
T = RequestResponseMap<R>, T = RequestResponseMap<R, APIVersion>,
>(command: string, response: T): void { >(command: string, response: T): void {
if (hasPartialPayment(command, response)) { if (hasPartialPayment(command, response)) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We are checking dynamically and safely. // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We are checking dynamically and safely.
@@ -138,10 +189,10 @@ export function handlePartialPayment<
* @param log - The method used for logging by the connection (to report the partial payment). * @param log - The method used for logging by the connection (to report the partial payment).
*/ */
export function handleStreamPartialPayment( export function handleStreamPartialPayment(
stream: TransactionStream, stream: TransactionStream | TransactionV1Stream,
log: (id: string, message: string) => void, log: (id: string, message: string) => void,
): void { ): void {
if (isPartialPayment(stream.transaction, stream.meta)) { if (isPartialPayment(stream.tx_json ?? stream.transaction, stream.meta)) {
const warnings = stream.warnings ?? [] const warnings = stream.warnings ?? []
const warning = { const warning = {

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 type LedgerIndex = number | ('validated' | 'closed' | 'current')
export interface XRP { export interface XRP {
@@ -16,6 +20,11 @@ export interface IssuedCurrencyAmount extends IssuedCurrency {
value: string value: string
} }
export interface MPTAmount {
mpt_issuance_id: string
value: string
}
export type Amount = IssuedCurrencyAmount | string export type Amount = IssuedCurrencyAmount | string
export interface Balance { export interface Balance {
@@ -104,6 +113,10 @@ export interface ResponseOnlyTxInfo {
* The sequence number of the ledger that included this transaction. * The sequence number of the ledger that included this transaction.
*/ */
ledger_index?: number ledger_index?: number
/**
* The hash of the ledger included this transaction.
*/
ledger_hash?: string
/** /**
* @deprecated Alias for ledger_index. * @deprecated Alias for ledger_index.
*/ */
@@ -149,9 +162,52 @@ export interface AuthAccount {
} }
} }
export interface AuthorizeCredential {
Credential: {
/** The issuer of the credential. */
Issuer: string
/** A hex-encoded value to identify the type of credential from the issuer. */
CredentialType: string
}
}
export interface XChainBridge { export interface XChainBridge {
LockingChainDoor: string LockingChainDoor: string
LockingChainIssue: Currency LockingChainIssue: Currency
IssuingChainDoor: string IssuingChainDoor: string
IssuingChainIssue: Currency 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

@@ -10,6 +10,7 @@ export * as LedgerEntry from './ledger'
export { export {
setTransactionFlagsToNumber, setTransactionFlagsToNumber,
parseAccountRootFlags, parseAccountRootFlags,
parseTransactionFlags,
} from './utils/flags' } from './utils/flags'
export * from './methods' export * from './methods'
export * from './transactions' export * from './transactions'

View File

@@ -1,6 +1,6 @@
import { AuthAccount, Currency, IssuedCurrencyAmount } from '../common' import { AuthAccount, Currency, IssuedCurrencyAmount } from '../common'
import { BaseLedgerEntry, MissingPreviousTxnID } from './BaseLedgerEntry' import { BaseLedgerEntry, HasOptionalPreviousTxnID } from './BaseLedgerEntry'
export interface VoteSlot { export interface VoteSlot {
VoteEntry: { VoteEntry: {
@@ -15,7 +15,7 @@ export interface VoteSlot {
* *
* @category Ledger Entries * @category Ledger Entries
*/ */
export default interface AMM extends BaseLedgerEntry, MissingPreviousTxnID { export default interface AMM extends BaseLedgerEntry, HasOptionalPreviousTxnID {
LedgerEntryType: 'AMM' LedgerEntryType: 'AMM'
/** /**
* The address of the special account that holds this AMM's assets. * 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 * 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 export default interface Amendments
extends BaseLedgerEntry, extends BaseLedgerEntry,
MissingPreviousTxnID { HasOptionalPreviousTxnID {
LedgerEntryType: 'Amendments' LedgerEntryType: 'Amendments'
/** /**
* Array of 256-bit amendment IDs for all currently-enabled amendments. If * Array of 256-bit amendment IDs for all currently-enabled amendments. If

View File

@@ -15,13 +15,17 @@ export interface HasPreviousTxnID {
PreviousTxnLgrSeq: number 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

@@ -0,0 +1,47 @@
import { GlobalFlags } from '../transactions/common'
import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'
export interface CredentialFlags extends GlobalFlags {
lsfAccepted?: boolean
}
/**
*
* A Credential object describes a credential, similar to a passport, which is an issuable identity verifier
* that can be used as a prerequisite for other transactions
*
* @category Ledger Entries
*/
export default interface Credential extends BaseLedgerEntry, HasPreviousTxnID {
LedgerEntryType: 'Credential'
/**
* A bit-map of boolean flags
*/
Flags: number | CredentialFlags
/** The account that the credential is for. */
Subject: string
/** The issuer of the credential. */
Issuer: string
/** A hex-encoded value to identify the type of credential from the issuer. */
CredentialType: string
/** A hint indicating which page of the subject's owner directory links to this object,
* in case the directory consists of multiple pages.
*/
SubjectNode: string
/** A hint indicating which page of the issuer's owner directory links to this object,
* in case the directory consists of multiple pages.
*/
IssuerNode: string
/** Credential expiration. */
Expiration?: number
/** Additional data about the credential (such as a link to the VC document). */
URI?: string
}

View File

@@ -1,3 +1,5 @@
import { AuthorizeCredential } from '../common'
import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry' import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'
/** /**
@@ -12,8 +14,6 @@ export default interface DepositPreauth
LedgerEntryType: 'DepositPreauth' LedgerEntryType: 'DepositPreauth'
/** The account that granted the preauthorization. */ /** The account that granted the preauthorization. */
Account: string Account: string
/** The account that received the preauthorization. */
Authorize: string
/** /**
* A bit-map of boolean flags. No flags are defined for DepositPreauth * A bit-map of boolean flags. No flags are defined for DepositPreauth
* objects, so this value is always 0. * objects, so this value is always 0.
@@ -24,4 +24,8 @@ export default interface DepositPreauth
* object, in case the directory consists of multiple pages. * object, in case the directory consists of multiple pages.
*/ */
OwnerNode: string OwnerNode: string
/** The account that received the preauthorization. */
Authorize?: string
/** The credential(s) that received the preauthorization. */
AuthorizeCredentials?: AuthorizeCredential[]
} }

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 * 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 export default interface DirectoryNode
extends BaseLedgerEntry, extends BaseLedgerEntry,
MissingPreviousTxnID { HasOptionalPreviousTxnID {
LedgerEntryType: 'DirectoryNode' LedgerEntryType: 'DirectoryNode'
/** /**
* A bit-map of boolean flags enabled for this directory. Currently, the * 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 * The unique id for the FeeSettings object https://xrpl.org/feesettings.html#feesettings-id-format
@@ -26,7 +26,9 @@ export interface FeeSettingsPostAmendmentFields {
ReserveIncrementDrops: string ReserveIncrementDrops: string
} }
export interface FeeSettingsBase extends BaseLedgerEntry, MissingPreviousTxnID { export interface FeeSettingsBase
extends BaseLedgerEntry,
HasOptionalPreviousTxnID {
LedgerEntryType: 'FeeSettings' LedgerEntryType: 'FeeSettings'
/** /**
* A bit-map of boolean flags for this object. No flags are defined for this type. * 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 { Transaction, TransactionMetadata } from '../transactions'
import { LedgerEntry } from './LedgerEntry' import { LedgerEntry } from './LedgerEntry'
/** /**
* A ledger is a block of transactions and shared state data. It has a unique * Common properties for ledger entries.
* header that describes its contents using cryptographic hashes.
* *
* @category Ledger Entries * @category Ledger Entries
*/ */
export default interface Ledger { interface BaseLedger {
/** The SHA-512Half of this ledger's state tree information. */ /** The SHA-512Half of this ledger's state tree information. */
account_hash: string account_hash: string
/** All the state information in this ledger. Admin only. */ /** All the state information in this ledger. Admin only. */
@@ -31,6 +31,11 @@ export default interface Ledger {
* by which the close_time could be rounded. * by which the close_time could be rounded.
*/ */
close_time_resolution: number close_time_resolution: number
/**
* The approximate time this ledger was closed, in date time string format.
* Always uses the UTC time zone.
*/
close_time_iso: string
/** Whether or not this ledger has been closed. */ /** Whether or not this ledger has been closed. */
closed: boolean closed: boolean
/** /**
@@ -38,11 +43,6 @@ export default interface Ledger {
* for this ledger and all its contents. * for this ledger and all its contents.
*/ */
ledger_hash: string 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. */ /** The approximate time at which the previous ledger was closed. */
parent_close_time: number parent_close_time: number
/** /**
@@ -61,5 +61,47 @@ export default interface Ledger {
* either JSON or binary depending on whether the request specified binary * either JSON or binary depending on whether the request specified binary
* as true. * 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

@@ -3,6 +3,7 @@ import Amendments from './Amendments'
import AMM from './AMM' import AMM from './AMM'
import Bridge from './Bridge' import Bridge from './Bridge'
import Check from './Check' import Check from './Check'
import Credential from './Credential'
import DepositPreauth from './DepositPreauth' import DepositPreauth from './DepositPreauth'
import DirectoryNode from './DirectoryNode' import DirectoryNode from './DirectoryNode'
import Escrow from './Escrow' import Escrow from './Escrow'
@@ -10,6 +11,7 @@ import FeeSettings from './FeeSettings'
import LedgerHashes from './LedgerHashes' import LedgerHashes from './LedgerHashes'
import NegativeUNL from './NegativeUNL' import NegativeUNL from './NegativeUNL'
import Offer from './Offer' import Offer from './Offer'
import Oracle from './Oracle'
import PayChannel from './PayChannel' import PayChannel from './PayChannel'
import RippleState from './RippleState' import RippleState from './RippleState'
import SignerList from './SignerList' import SignerList from './SignerList'
@@ -23,6 +25,7 @@ type LedgerEntry =
| AMM | AMM
| Bridge | Bridge
| Check | Check
| Credential
| DepositPreauth | DepositPreauth
| DirectoryNode | DirectoryNode
| Escrow | Escrow
@@ -30,6 +33,7 @@ type LedgerEntry =
| LedgerHashes | LedgerHashes
| NegativeUNL | NegativeUNL
| Offer | Offer
| Oracle
| PayChannel | PayChannel
| RippleState | RippleState
| SignerList | SignerList
@@ -43,15 +47,19 @@ type LedgerEntryFilter =
| 'amm' | 'amm'
| 'bridge' | 'bridge'
| 'check' | 'check'
| 'credential'
| 'deposit_preauth' | 'deposit_preauth'
| 'did' | 'did'
| 'directory' | 'directory'
| 'escrow' | 'escrow'
| 'fee' | 'fee'
| 'hashes' | 'hashes'
| 'mpt_issuance'
| 'mptoken'
| 'nft_offer' | 'nft_offer'
| 'nft_page' | 'nft_page'
| 'offer' | 'offer'
| 'oracle'
| 'payment_channel' | 'payment_channel'
| 'signer_list' | 'signer_list'
| 'state' | '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 * 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 * @category Ledger Entries
*/ */
export default interface LedgerHashes export default interface LedgerHashes extends BaseLedgerEntry {
extends BaseLedgerEntry,
MissingPreviousTxnID {
LedgerEntryType: 'LedgerHashes' LedgerEntryType: 'LedgerHashes'
/** The Ledger Index of the last entry in this object's Hashes array. */ /** The Ledger Index of the last entry in this object's Hashes array. */
LastLedgerSequence?: number LastLedgerSequence?: number

View File

@@ -0,0 +1,11 @@
import { MPTAmount } from '../common'
import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'
export interface MPToken extends BaseLedgerEntry, HasPreviousTxnID {
LedgerEntryType: 'MPToken'
MPTokenIssuanceID: string
MPTAmount?: MPTAmount
Flags: number
OwnerNode?: string
}

View File

@@ -0,0 +1,13 @@
import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'
export interface MPTokenIssuance extends BaseLedgerEntry, HasPreviousTxnID {
LedgerEntryType: 'MPTokenIssuance'
Flags: number
Issuer: string
AssetScale?: number
MaximumAmount?: string
OutstandingAmount: string
TransferFee?: number
MPTokenMetadata?: string
OwnerNode?: string
}

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 * 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 export default interface NegativeUNL
extends BaseLedgerEntry, extends BaseLedgerEntry,
MissingPreviousTxnID { HasOptionalPreviousTxnID {
LedgerEntryType: 'NegativeUNL' LedgerEntryType: 'NegativeUNL'
/** /**
* A list of trusted validators that are currently disabled. * 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, lsfLowFreeze = 0x00400000,
// True, high side has set freeze flag // True, high side has set freeze flag
lsfHighFreeze = 0x00800000, lsfHighFreeze = 0x00800000,
// True, trust line to AMM. Used by client apps to identify payments via AMM.
lsfAMMNode = 0x01000000,
} }

View File

@@ -6,6 +6,7 @@ import Amendments, { Majority, AMENDMENTS_ID } from './Amendments'
import AMM, { VoteSlot } from './AMM' import AMM, { VoteSlot } from './AMM'
import Bridge from './Bridge' import Bridge from './Bridge'
import Check from './Check' import Check from './Check'
import Credential from './Credential'
import DepositPreauth from './DepositPreauth' import DepositPreauth from './DepositPreauth'
import DID from './DID' import DID from './DID'
import DirectoryNode from './DirectoryNode' import DirectoryNode from './DirectoryNode'
@@ -15,13 +16,16 @@ import FeeSettings, {
FeeSettingsPostAmendmentFields, FeeSettingsPostAmendmentFields,
FEE_SETTINGS_ID, FEE_SETTINGS_ID,
} from './FeeSettings' } from './FeeSettings'
import Ledger from './Ledger' import { Ledger, LedgerV1 } from './Ledger'
import { LedgerEntry, LedgerEntryFilter } from './LedgerEntry' import { LedgerEntry, LedgerEntryFilter } from './LedgerEntry'
import LedgerHashes from './LedgerHashes' import LedgerHashes from './LedgerHashes'
import { MPToken } from './MPToken'
import { MPTokenIssuance } from './MPTokenIssuance'
import NegativeUNL, { NEGATIVE_UNL_ID } from './NegativeUNL' import NegativeUNL, { NEGATIVE_UNL_ID } from './NegativeUNL'
import { NFTokenOffer } from './NFTokenOffer' import { NFTokenOffer } from './NFTokenOffer'
import { NFToken, NFTokenPage } from './NFTokenPage' import { NFToken, NFTokenPage } from './NFTokenPage'
import Offer, { OfferFlags } from './Offer' import Offer, { OfferFlags } from './Offer'
import Oracle from './Oracle'
import PayChannel from './PayChannel' import PayChannel from './PayChannel'
import RippleState, { RippleStateFlags } from './RippleState' import RippleState, { RippleStateFlags } from './RippleState'
import SignerList, { SignerListFlags } from './SignerList' import SignerList, { SignerListFlags } from './SignerList'
@@ -38,6 +42,7 @@ export {
AMM, AMM,
Bridge, Bridge,
Check, Check,
Credential,
DepositPreauth, DepositPreauth,
DirectoryNode, DirectoryNode,
DID, DID,
@@ -47,17 +52,21 @@ export {
FeeSettingsPreAmendmentFields, FeeSettingsPreAmendmentFields,
FeeSettingsPostAmendmentFields, FeeSettingsPostAmendmentFields,
Ledger, Ledger,
LedgerV1,
LedgerEntryFilter, LedgerEntryFilter,
LedgerEntry, LedgerEntry,
LedgerHashes, LedgerHashes,
Majority, Majority,
NEGATIVE_UNL_ID, NEGATIVE_UNL_ID,
NegativeUNL, NegativeUNL,
MPTokenIssuance,
MPToken,
NFTokenOffer, NFTokenOffer,
NFTokenPage, NFTokenPage,
NFToken, NFToken,
Offer, Offer,
OfferFlags, OfferFlags,
Oracle,
PayChannel, PayChannel,
RippleState, RippleState,
RippleStateFlags, RippleStateFlags,

View File

@@ -1,17 +1,80 @@
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod' import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
/**
* Represents a payment channel in the XRP Ledger.
*/
export interface Channel { export interface Channel {
/** The owner of the channel, as an Address. */
account: string account: string
/** The total amount of XRP, in drops allocated to this channel. */
amount: string 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 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 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 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 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 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 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 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 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 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 { AccountRoot, SignerList } from '../ledger'
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod' import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
@@ -133,23 +134,13 @@ export interface AccountInfoAccountFlags {
allowTrustLineClawback: boolean allowTrustLineClawback: boolean
} }
/** interface BaseAccountInfoResponse extends BaseResponse {
* Response expected from an {@link AccountInfoRequest}.
*
* @category Responses
*/
export interface AccountInfoResponse extends BaseResponse {
result: { result: {
/** /**
* The AccountRoot ledger object with this account's information, as stored * The AccountRoot ledger object with this account's information, as stored
* in the ledger. * 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. * 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 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 { Transaction, TransactionMetadata } from '../transactions'
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod' import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
@@ -49,7 +55,9 @@ export interface AccountTxRequest extends BaseRequest, LookupByLedgerRequest {
marker?: unknown 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. */ /** The ledger index of the ledger version that included this transaction. */
ledger_index: number ledger_index: number
/** /**
@@ -58,7 +66,15 @@ export interface AccountTxTransaction {
*/ */
meta: string | TransactionMetadata meta: string | TransactionMetadata
/** JSON object defining the transaction. */ /** 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. */ /** Unique hashed String representing the transaction. */
tx_blob?: string tx_blob?: string
/** /**
@@ -69,11 +85,11 @@ export interface AccountTxTransaction {
} }
/** /**
* Expected response from an {@link AccountTxRequest}. * Base interface for account transaction responses.
*
* @category Responses
*/ */
export interface AccountTxResponse extends BaseResponse { interface AccountTxResponseBase<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> extends BaseResponse {
result: { result: {
/** Unique Address identifying the related account. */ /** Unique Address identifying the related account. */
account: string account: string
@@ -98,7 +114,7 @@ export interface AccountTxResponse extends BaseResponse {
* Array of transactions matching the request's criteria, as explained * Array of transactions matching the request's criteria, as explained
* below. * below.
*/ */
transactions: AccountTxTransaction[] transactions: Array<AccountTxTransaction<Version>>
/** /**
* If included and set to true, the information in this response comes from * If included and set to true, the information in this response comes from
* a validated ledger version. Otherwise, the information is subject to * a validated ledger version. Otherwise, the information is subject to
@@ -107,3 +123,28 @@ export interface AccountTxResponse extends BaseResponse {
validated?: boolean 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

@@ -15,6 +15,12 @@ export interface DepositAuthorizedRequest
source_account: string source_account: string
/** The recipient of a possible payment. */ /** The recipient of a possible payment. */
destination_account: string destination_account: string
/**
* The object IDs of Credential objects. If this field is included, then the
* credential will be taken into account when analyzing whether the sender can send
* funds to the destination.
*/
credentials?: string[]
} }
/** /**
@@ -52,5 +58,9 @@ export interface DepositAuthorizedResponse extends BaseResponse {
source_account: string source_account: string
/** If true, the information comes from a validated ledger version. */ /** If true, the information comes from a validated ledger version. */
validated?: boolean validated?: boolean
/** The object IDs of `Credential` objects. If this field is included,
* then the credential will be taken into account when analyzing whether
* the sender can send funds to the destination. */
credentials?: string[]
} }
} }

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 no-inline-comments -- Necessary for important note */
/* eslint-disable max-lines -- There is a lot to export */ /* eslint-disable max-lines -- There is a lot to export */
import type { APIVersion, DEFAULT_API_VERSION } from '../common'
import { import {
AccountChannelsRequest, AccountChannelsRequest,
AccountChannelsResponse, AccountChannelsResponse,
@@ -13,6 +15,8 @@ import {
AccountInfoAccountFlags, AccountInfoAccountFlags,
AccountInfoRequest, AccountInfoRequest,
AccountInfoResponse, AccountInfoResponse,
AccountInfoV1Response,
AccountInfoVersionResponseMap,
AccountQueueData, AccountQueueData,
AccountQueueTransaction, AccountQueueTransaction,
} from './accountInfo' } from './accountInfo'
@@ -40,6 +44,8 @@ import {
import { import {
AccountTxRequest, AccountTxRequest,
AccountTxResponse, AccountTxResponse,
AccountTxV1Response,
AccountTxVersionResponseMap,
AccountTxTransaction, AccountTxTransaction,
} from './accountTx' } from './accountTx'
import { AMMInfoRequest, AMMInfoResponse } from './ammInfo' import { AMMInfoRequest, AMMInfoResponse } from './ammInfo'
@@ -60,23 +66,37 @@ import {
DepositAuthorizedRequest, DepositAuthorizedRequest,
DepositAuthorizedResponse, DepositAuthorizedResponse,
} from './depositAuthorized' } from './depositAuthorized'
import {
FeatureAllRequest,
FeatureAllResponse,
FeatureOneRequest,
FeatureOneResponse,
FeatureRequest,
FeatureResponse,
} from './feature'
import { FeeRequest, FeeResponse } from './fee' import { FeeRequest, FeeResponse } from './fee'
import { import {
GatewayBalance, GatewayBalance,
GatewayBalancesRequest, GatewayBalancesRequest,
GatewayBalancesResponse, GatewayBalancesResponse,
} from './gatewayBalances' } from './gatewayBalances'
import {
GetAggregatePriceRequest,
GetAggregatePriceResponse,
} from './getAggregatePrice'
import { import {
LedgerBinary, LedgerBinary,
LedgerModifiedOfferCreateTransaction, LedgerModifiedOfferCreateTransaction,
LedgerQueueData, LedgerQueueData,
LedgerRequest, LedgerRequest,
LedgerResponse, LedgerResponse,
LedgerV1Response,
LedgerRequestExpandedTransactionsOnly, LedgerRequestExpandedTransactionsOnly,
LedgerResponseExpanded, LedgerResponseExpanded,
LedgerRequestExpandedAccountsAndTransactions, LedgerRequestExpandedAccountsAndTransactions,
LedgerRequestExpandedAccountsOnly, LedgerRequestExpandedAccountsOnly,
LedgerRequestExpandedTransactionsBinary, LedgerRequestExpandedTransactionsBinary,
LedgerVersionResponseMap,
} from './ledger' } from './ledger'
import { LedgerClosedRequest, LedgerClosedResponse } from './ledgerClosed' import { LedgerClosedRequest, LedgerClosedResponse } from './ledgerClosed'
import { LedgerCurrentRequest, LedgerCurrentResponse } from './ledgerCurrent' import { LedgerCurrentRequest, LedgerCurrentResponse } from './ledgerCurrent'
@@ -96,6 +116,7 @@ import {
NFTHistoryTransaction, NFTHistoryTransaction,
} from './nftHistory' } from './nftHistory'
import { NFTInfoRequest, NFTInfoResponse } from './nftInfo' import { NFTInfoRequest, NFTInfoResponse } from './nftInfo'
import { NFTsByIssuerRequest, NFTsByIssuerResponse } from './nftsByIssuer'
import { NFTSellOffersRequest, NFTSellOffersResponse } from './nftSellOffers' import { NFTSellOffersRequest, NFTSellOffersResponse } from './nftSellOffers'
import { NoRippleCheckRequest, NoRippleCheckResponse } from './norippleCheck' import { NoRippleCheckRequest, NoRippleCheckResponse } from './norippleCheck'
import { import {
@@ -131,6 +152,8 @@ import { SubmitRequest, SubmitResponse } from './submit'
import { import {
SubmitMultisignedRequest, SubmitMultisignedRequest,
SubmitMultisignedResponse, SubmitMultisignedResponse,
SubmitMultisignedV1Response,
SubmitMultisignedVersionResponseMap,
} from './submitMultisigned' } from './submitMultisigned'
import { import {
BooksSnapshot, BooksSnapshot,
@@ -145,13 +168,14 @@ import {
SubscribeRequest, SubscribeRequest,
SubscribeResponse, SubscribeResponse,
TransactionStream, TransactionStream,
TransactionV1Stream,
ValidationStream, ValidationStream,
} from './subscribe' } from './subscribe'
import { import {
TransactionEntryRequest, TransactionEntryRequest,
TransactionEntryResponse, TransactionEntryResponse,
} from './transactionEntry' } from './transactionEntry'
import { TxRequest, TxResponse } from './tx' import { TxRequest, TxResponse, TxV1Response, TxVersionResponseMap } from './tx'
import { import {
UnsubscribeBook, UnsubscribeBook,
UnsubscribeRequest, UnsubscribeRequest,
@@ -199,6 +223,7 @@ type Request =
| ServerDefinitionsRequest | ServerDefinitionsRequest
| ServerInfoRequest | ServerInfoRequest
| ServerStateRequest | ServerStateRequest
| FeatureRequest
// utility methods // utility methods
| PingRequest | PingRequest
| RandomRequest | RandomRequest
@@ -208,33 +233,36 @@ type Request =
// clio only methods // clio only methods
| NFTInfoRequest | NFTInfoRequest
| NFTHistoryRequest | NFTHistoryRequest
| NFTsByIssuerRequest
// AMM methods // AMM methods
| AMMInfoRequest | AMMInfoRequest
// Price Oracle methods
| GetAggregatePriceRequest
/** /**
* @category Responses * @category Responses
*/ */
type Response = type Response<Version extends APIVersion = typeof DEFAULT_API_VERSION> =
// account methods // account methods
| AccountChannelsResponse | AccountChannelsResponse
| AccountCurrenciesResponse | AccountCurrenciesResponse
| AccountInfoResponse | AccountInfoVersionResponseMap<Version>
| AccountLinesResponse | AccountLinesResponse
| AccountNFTsResponse | AccountNFTsResponse
| AccountObjectsResponse | AccountObjectsResponse
| AccountOffersResponse | AccountOffersResponse
| AccountTxResponse | AccountTxVersionResponseMap<Version>
| GatewayBalancesResponse | GatewayBalancesResponse
| NoRippleCheckResponse | NoRippleCheckResponse
// ledger methods // ledger methods
| LedgerResponse | LedgerVersionResponseMap<Version>
| LedgerClosedResponse | LedgerClosedResponse
| LedgerCurrentResponse | LedgerCurrentResponse
| LedgerDataResponse | LedgerDataResponse
| LedgerEntryResponse | LedgerEntryResponse
// transaction methods // transaction methods
| SubmitResponse | SubmitResponse
| SubmitMultisignedResponse | SubmitMultisignedVersionResponseMap<Version>
| TransactionEntryResponse | TransactionEntryResponse
| TxResponse | TxResponse
// path and order book methods // path and order book methods
@@ -253,6 +281,7 @@ type Response =
| ServerDefinitionsResponse | ServerDefinitionsResponse
| ServerInfoResponse | ServerInfoResponse
| ServerStateResponse | ServerStateResponse
| FeatureResponse
// utility methods // utility methods
| PingResponse | PingResponse
| RandomResponse | RandomResponse
@@ -262,15 +291,21 @@ type Response =
// clio only methods // clio only methods
| NFTInfoResponse | NFTInfoResponse
| NFTHistoryResponse | NFTHistoryResponse
| NFTsByIssuerResponse
// AMM methods // AMM methods
| AMMInfoResponse | 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 ? AccountChannelsResponse
: T extends AccountCurrenciesRequest : T extends AccountCurrenciesRequest
? AccountCurrenciesResponse ? AccountCurrenciesResponse
: T extends AccountInfoRequest : T extends AccountInfoRequest
? AccountInfoResponse ? AccountInfoVersionResponseMap<Version>
: T extends AccountLinesRequest : T extends AccountLinesRequest
? AccountLinesResponse ? AccountLinesResponse
: T extends AccountNFTsRequest : T extends AccountNFTsRequest
@@ -280,11 +315,13 @@ export type RequestResponseMap<T> = T extends AccountChannelsRequest
: T extends AccountOffersRequest : T extends AccountOffersRequest
? AccountOffersResponse ? AccountOffersResponse
: T extends AccountTxRequest : T extends AccountTxRequest
? AccountTxResponse ? AccountTxVersionResponseMap<Version>
: T extends AMMInfoRequest : T extends AMMInfoRequest
? AMMInfoResponse ? AMMInfoResponse
: T extends GatewayBalancesRequest : T extends GatewayBalancesRequest
? GatewayBalancesResponse ? GatewayBalancesResponse
: T extends GetAggregatePriceRequest
? GetAggregatePriceResponse
: T extends NoRippleCheckRequest : T extends NoRippleCheckRequest
? NoRippleCheckResponse ? NoRippleCheckResponse
: // NOTE: The order of these LedgerRequest types is important : // NOTE: The order of these LedgerRequest types is important
@@ -344,15 +381,15 @@ export type RequestResponseMap<T> = T extends AccountChannelsRequest
// then we'd get the wrong response type, LedgerResponse, instead of // then we'd get the wrong response type, LedgerResponse, instead of
// LedgerResponseExpanded. // LedgerResponseExpanded.
T extends LedgerRequestExpandedTransactionsBinary T extends LedgerRequestExpandedTransactionsBinary
? LedgerResponse ? LedgerVersionResponseMap<Version>
: T extends LedgerRequestExpandedAccountsAndTransactions : T extends LedgerRequestExpandedAccountsAndTransactions
? LedgerResponseExpanded ? LedgerResponseExpanded<Version>
: T extends LedgerRequestExpandedTransactionsOnly : T extends LedgerRequestExpandedTransactionsOnly
? LedgerResponseExpanded ? LedgerResponseExpanded<Version>
: T extends LedgerRequestExpandedAccountsOnly : T extends LedgerRequestExpandedAccountsOnly
? LedgerResponseExpanded ? LedgerResponseExpanded<Version>
: T extends LedgerRequest : T extends LedgerRequest
? LedgerResponse ? LedgerVersionResponseMap<Version>
: T extends LedgerClosedRequest : T extends LedgerClosedRequest
? LedgerClosedResponse ? LedgerClosedResponse
: T extends LedgerCurrentRequest : T extends LedgerCurrentRequest
@@ -364,11 +401,11 @@ export type RequestResponseMap<T> = T extends AccountChannelsRequest
: T extends SubmitRequest : T extends SubmitRequest
? SubmitResponse ? SubmitResponse
: T extends SubmitMultisignedRequest : T extends SubmitMultisignedRequest
? SubmitMultisignedResponse ? SubmitMultisignedVersionResponseMap<Version>
: T extends TransactionEntryRequest : T extends TransactionEntryRequest
? TransactionEntryResponse ? TransactionEntryResponse
: T extends TxRequest : T extends TxRequest
? TxResponse ? TxVersionResponseMap<Version>
: T extends BookOffersRequest : T extends BookOffersRequest
? BookOffersResponse ? BookOffersResponse
: T extends DepositAuthorizedRequest : T extends DepositAuthorizedRequest
@@ -393,6 +430,10 @@ export type RequestResponseMap<T> = T extends AccountChannelsRequest
? ServerStateResponse ? ServerStateResponse
: T extends ServerDefinitionsRequest : T extends ServerDefinitionsRequest
? ServerDefinitionsResponse ? ServerDefinitionsResponse
: T extends FeatureAllRequest
? FeatureAllResponse
: T extends FeatureOneRequest
? FeatureOneResponse
: T extends PingRequest : T extends PingRequest
? PingResponse ? PingResponse
: T extends RandomRequest : T extends RandomRequest
@@ -403,22 +444,29 @@ export type RequestResponseMap<T> = T extends AccountChannelsRequest
? NFTSellOffersResponse ? NFTSellOffersResponse
: T extends NFTInfoRequest : T extends NFTInfoRequest
? NFTInfoResponse ? NFTInfoResponse
: T extends NFTsByIssuerRequest
? NFTsByIssuerResponse
: T extends NFTHistoryRequest : T extends NFTHistoryRequest
? NFTHistoryResponse ? NFTHistoryResponse
: Response : Response<Version>
export type MarkerRequest = Request & { export type MarkerRequest = Request & {
limit?: number limit?: number
marker?: unknown marker?: unknown
} }
export type MarkerResponse = Response & { export type MarkerResponse<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = Response<Version> & {
result: { result: {
marker?: unknown marker?: unknown
} }
} }
export type RequestAllResponseMap<T> = T extends AccountChannelsRequest export type RequestAllResponseMap<
T,
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> = T extends AccountChannelsRequest
? AccountChannelsResponse ? AccountChannelsResponse
: T extends AccountLinesRequest : T extends AccountLinesRequest
? AccountLinesResponse ? AccountLinesResponse
@@ -427,14 +475,12 @@ export type RequestAllResponseMap<T> = T extends AccountChannelsRequest
: T extends AccountOffersRequest : T extends AccountOffersRequest
? AccountOffersResponse ? AccountOffersResponse
: T extends AccountTxRequest : T extends AccountTxRequest
? AccountTxResponse ? AccountTxVersionResponseMap<Version>
: T extends LedgerDataRequest : T extends LedgerDataRequest
? LedgerDataResponse ? LedgerDataResponse
: T extends AccountTxRequest
? AccountTxResponse
: T extends BookOffersRequest : T extends BookOffersRequest
? BookOffersResponse ? BookOffersResponse
: MarkerResponse : MarkerResponse<Version>
export { export {
// Allow users to define their own requests and responses. This is useful for releasing experimental versions // Allow users to define their own requests and responses. This is useful for releasing experimental versions
@@ -452,6 +498,7 @@ export {
AccountInfoAccountFlags, AccountInfoAccountFlags,
AccountInfoRequest, AccountInfoRequest,
AccountInfoResponse, AccountInfoResponse,
AccountInfoV1Response,
AccountQueueData, AccountQueueData,
AccountQueueTransaction, AccountQueueTransaction,
AccountLinesRequest, AccountLinesRequest,
@@ -469,15 +516,19 @@ export {
AccountOffersResponse, AccountOffersResponse,
AccountTxRequest, AccountTxRequest,
AccountTxResponse, AccountTxResponse,
AccountTxV1Response,
AccountTxTransaction, AccountTxTransaction,
GatewayBalance, GatewayBalance,
GatewayBalancesRequest, GatewayBalancesRequest,
GatewayBalancesResponse, GatewayBalancesResponse,
GetAggregatePriceRequest,
GetAggregatePriceResponse,
NoRippleCheckRequest, NoRippleCheckRequest,
NoRippleCheckResponse, NoRippleCheckResponse,
// ledger methods // ledger methods
LedgerRequest, LedgerRequest,
LedgerResponse, LedgerResponse,
LedgerV1Response,
LedgerQueueData, LedgerQueueData,
LedgerBinary, LedgerBinary,
LedgerModifiedOfferCreateTransaction, LedgerModifiedOfferCreateTransaction,
@@ -497,10 +548,12 @@ export {
SubmitResponse, SubmitResponse,
SubmitMultisignedRequest, SubmitMultisignedRequest,
SubmitMultisignedResponse, SubmitMultisignedResponse,
SubmitMultisignedV1Response,
TransactionEntryRequest, TransactionEntryRequest,
TransactionEntryResponse, TransactionEntryResponse,
TxRequest, TxRequest,
TxResponse, TxResponse,
TxV1Response,
// path and order book methods with types // path and order book methods with types
BookOffersRequest, BookOffersRequest,
BookOffer, BookOffer,
@@ -531,6 +584,7 @@ export {
LedgerStreamResponse, LedgerStreamResponse,
ValidationStream, ValidationStream,
TransactionStream, TransactionStream,
TransactionV1Stream,
PathFindStream, PathFindStream,
PeerStatusStream, PeerStatusStream,
OrderBookStream, OrderBookStream,
@@ -553,6 +607,8 @@ export {
ServerState, ServerState,
StateAccountingFinal, StateAccountingFinal,
StateAccounting, StateAccounting,
FeatureRequest,
FeatureResponse,
// utility methods // utility methods
PingRequest, PingRequest,
PingResponse, PingResponse,
@@ -570,6 +626,8 @@ export {
NFTHistoryRequest, NFTHistoryRequest,
NFTHistoryResponse, NFTHistoryResponse,
NFTHistoryTransaction, NFTHistoryTransaction,
NFTsByIssuerRequest,
NFTsByIssuerResponse,
// AMM methods // AMM methods
AMMInfoRequest, AMMInfoRequest,
AMMInfoResponse, 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 { LedgerEntryFilter } from '../ledger/LedgerEntry'
import { Transaction, TransactionAndMetadata } from '../transactions' import { Transaction, TransactionAndMetadata } from '../transactions'
import { TransactionMetadata } from '../transactions/metadata' import { TransactionMetadata } from '../transactions/metadata'
@@ -207,6 +208,12 @@ export interface LedgerBinary
transactions?: string[] transactions?: string[]
} }
export interface LedgerBinaryV1
extends Omit<Omit<LedgerV1, 'transactions'>, 'accountState'> {
accountState?: string[]
transactions?: string[]
}
interface LedgerResponseBase { interface LedgerResponseBase {
/** Unique identifying hash of the entire ledger. */ /** Unique identifying hash of the entire ledger. */
ledger_hash: string ledger_hash: string
@@ -231,6 +238,11 @@ interface LedgerResponseResult extends LedgerResponseBase {
ledger: LedgerBinary ledger: LedgerBinary
} }
interface LedgerV1ResponseResult extends LedgerResponseBase {
/** The complete header data of this {@link Ledger}. */
ledger: LedgerBinaryV1
}
/** /**
* Response expected from a {@link LedgerRequest}. * Response expected from a {@link LedgerRequest}.
* This is the default request response, triggered when `expand` and `binary` are both false. * 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 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}. */ /** The complete header data of this {@link Ledger}. */
ledger: Ledger ledger: LedgerVersionMap<Version>
} }
/** /**
@@ -254,6 +288,8 @@ interface LedgerResponseExpandedResult extends LedgerResponseBase {
* *
* @category Responses * @category Responses
*/ */
export interface LedgerResponseExpanded extends BaseResponse { export interface LedgerResponseExpanded<
result: LedgerResponseExpandedResult Version extends APIVersion = typeof DEFAULT_API_VERSION,
> extends BaseResponse {
result: LedgerResponseExpandedResult<Version>
} }

View File

@@ -21,6 +21,22 @@ import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
*/ */
export interface LedgerEntryRequest extends BaseRequest, LookupByLedgerRequest { export interface LedgerEntryRequest extends BaseRequest, LookupByLedgerRequest {
command: 'ledger_entry' command: 'ledger_entry'
/**
* Retrieve a MPTokenIssuance object from the ledger.
*/
mpt_issuance?: string
/**
* Retrieve a MPToken object from the ledger.
*/
mptoken?:
| {
mpt_issuance_id: string
account: string
}
| string
/** /**
* Retrieve an Automated Market Maker (AMM) object from the ledger. * Retrieve an Automated Market Maker (AMM) object from the ledger.
* This is similar to amm_info method, but the ledger_entry version returns only the ledger entry as stored. * This is similar to amm_info method, but the ledger_entry version returns only the ledger entry as stored.
@@ -35,7 +51,14 @@ export interface LedgerEntryRequest extends BaseRequest, LookupByLedgerRequest {
issuer?: string issuer?: string
} }
} }
/**
* (Optional) If set to true and the queried object has been deleted,
* return its complete data prior to its deletion.
* If set to false or not provided and the queried object has been deleted,
* return objectNotFound (current behavior).
* This parameter is supported only by Clio servers
*/
include_deleted?: boolean
/** /**
* If true, return the requested ledger object's contents as a hex string in * If true, return the requested ledger object's contents as a hex string in
* the XRP Ledger's binary format. Otherwise, return data in JSON format. The * the XRP Ledger's binary format. Otherwise, return data in JSON format. The
@@ -60,6 +83,23 @@ export interface LedgerEntryRequest extends BaseRequest, LookupByLedgerRequest {
/** The object ID of a Check object to retrieve. */ /** The object ID of a Check object to retrieve. */
check?: string check?: string
/* Specify the Credential to retrieve. If a string, must be the ledger entry ID of
* the entry, as hexadecimal. If an object, requires subject, issuer, and
* credential_type sub-fields.
*/
credential?:
| {
/** The account that is the subject of the credential. */
subject: string
/** The account that issued the credential. */
issuer: string
/** The type of the credential, as issued. */
credentialType: string
}
| string
/** /**
* Specify a DepositPreauth object to retrieve. If a string, must be the * Specify a DepositPreauth object to retrieve. If a string, must be the
* object ID of the DepositPreauth object, as hexadecimal. If an object, * object ID of the DepositPreauth object, as hexadecimal. If an object,
@@ -204,5 +244,9 @@ export interface LedgerEntryResponse<T = LedgerEntry> extends BaseResponse {
/** The binary representation of the ledger object, as hexadecimal. */ /** The binary representation of the ledger object, as hexadecimal. */
node_binary?: string node_binary?: string
validated?: boolean validated?: boolean
/**
* (Optional) Indicates the ledger index at which the object was deleted.
*/
deleted_ledger_index?: number
} }
} }

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 { Transaction } from '../transactions'
import { BaseRequest, BaseResponse } from './baseMethod' import { BaseRequest, BaseResponse } from './baseMethod'
@@ -24,28 +25,59 @@ export interface SubmitMultisignedRequest extends BaseRequest {
fail_hard?: boolean 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}. * Response expected from a {@link SubmitMultisignedRequest}.
* *
* @category Responses * @category Responses
*/ */
export interface SubmitMultisignedResponse extends BaseResponse { export interface SubmitMultisignedResponse extends BaseResponse {
result: { result: BaseSubmitMultisignedResult & {
/** hash?: string
* Code indicating the preliminary result of the transaction, for example. }
* `tesSUCCESS` . }
*/
engine_result: string /**
/** * Response expected from a {@link SubmitMultisignedRequest} using api_version 1.
* Numeric code indicating the preliminary result of the transaction, *
* directly correlated to `engine_result`. * @category ResponsesV1
*/ */
engine_result_code: number export interface SubmitMultisignedV1Response extends BaseResponse {
/** Human-readable explanation of the preliminary transaction result. */ result: BaseSubmitMultisignedResult & {
engine_result_message: string
/** The complete transaction in hex string format. */
tx_blob: string
/** The complete transaction in JSON format. */
tx_json: Transaction & { hash?: string } 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

@@ -4,6 +4,10 @@ import type {
Path, Path,
StreamType, StreamType,
ResponseOnlyTxInfo, ResponseOnlyTxInfo,
APIVersion,
DEFAULT_API_VERSION,
RIPPLED_API_V1,
RIPPLED_API_V2,
} from '../common' } from '../common'
import { Offer } from '../ledger' import { Offer } from '../ledger'
import { OfferCreate, Transaction } from '../transactions' import { OfferCreate, Transaction } from '../transactions'
@@ -262,9 +266,16 @@ export interface ValidationStream extends BaseStream {
* *
* @category Streams * @category Streams
*/ */
export interface TransactionStream extends BaseStream { interface TransactionStreamBase<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
> extends BaseStream {
status: string status: string
type: 'transaction' type: 'transaction'
/**
* The approximate time this ledger was closed, in date time string format.
* Always uses the UTC time zone.
*/
close_time_iso: string
/** String Transaction result code. */ /** String Transaction result code. */
engine_result: string engine_result: string
/** Numeric transaction response code, if applicable. */ /** Numeric transaction response code, if applicable. */
@@ -285,8 +296,14 @@ export interface TransactionStream extends BaseStream {
* in detail. * in detail.
*/ */
meta?: TransactionMetadata meta?: TransactionMetadata
/** The definition of the transaction in JSON format. */ /** JSON object defining the transaction. */
transaction: Transaction & ResponseOnlyTxInfo tx_json?: Version extends typeof RIPPLED_API_V2
? Transaction & ResponseOnlyTxInfo
: never
/** JSON object defining the transaction in rippled API v1. */
transaction?: Version extends typeof RIPPLED_API_V1
? Transaction & ResponseOnlyTxInfo
: never
/** /**
* If true, this transaction is included in a validated ledger and its * If true, this transaction is included in a validated ledger and its
* outcome is final. Responses from the transaction stream should always be * outcome is final. Responses from the transaction stream should always be
@@ -296,6 +313,20 @@ export interface TransactionStream extends BaseStream {
warnings?: Array<{ id: number; message: string }> warnings?: Array<{ id: number; message: string }>
} }
/**
* Expected response from an {@link AccountTxRequest}.
*
* @category Streams
*/
export type TransactionStream = TransactionStreamBase
/**
* Expected response from an {@link AccountTxRequest} with `api_version` set to 1.
*
* @category Streams
*/
export type TransactionV1Stream = TransactionStreamBase<typeof RIPPLED_API_V1>
/** /**
* The admin-only `peer_status` stream reports a large amount of information on * The admin-only `peer_status` stream reports a large amount of information on
* the activities of other rippled servers to which this server is connected, in * the activities of other rippled servers to which this server is connected, in

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 { Transaction, TransactionMetadata } from '../transactions'
import { BaseTransaction } from '../transactions/common' import { BaseTransaction } from '../transactions/common'
@@ -41,6 +47,47 @@ export interface TxRequest extends BaseRequest {
max_ledger?: number 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}. * Response expected from a {@link TxRequest}.
* *
@@ -48,28 +95,7 @@ export interface TxRequest extends BaseRequest {
*/ */
export interface TxResponse<T extends BaseTransaction = Transaction> export interface TxResponse<T extends BaseTransaction = Transaction>
extends BaseResponse { extends BaseResponse {
result: { result: BaseTxResult<typeof RIPPLED_API_V2, T> & { tx_json: T }
/** 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
/** /**
* If true, the server was able to search all of the specified ledger * 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 * 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 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, tfTwoAsset = 0x00100000,
tfOneAssetLPToken = 0x00200000, tfOneAssetLPToken = 0x00200000,
tfLimitLPToken = 0x00400000, tfLimitLPToken = 0x00400000,
tfTwoAssetIfEmpty = 0x00800000,
} }
export interface AMMDepositFlagsInterface extends GlobalFlags { export interface AMMDepositFlagsInterface extends GlobalFlags {
@@ -29,6 +30,7 @@ export interface AMMDepositFlagsInterface extends GlobalFlags {
tfTwoAsset?: boolean tfTwoAsset?: boolean
tfOneAssetLPToken?: boolean tfOneAssetLPToken?: boolean
tfLimitLPToken?: boolean tfLimitLPToken?: boolean
tfTwoAssetIfEmpty?: boolean
} }
/** /**

View File

@@ -0,0 +1,44 @@
import {
BaseTransaction,
isString,
validateBaseTransaction,
validateCredentialType,
validateRequiredField,
} from './common'
/**
* Accepts a credential issued to the Account (i.e. the Account is the Subject of the Credential object).
* Credentials are represented in hex. Whilst they are allowed a maximum length of 64
* bytes, every byte requires 2 hex characters for representation.
* The credential is not considered valid until it has been transferred/accepted.
*
* @category Transaction Models
* */
export interface CredentialAccept extends BaseTransaction {
TransactionType: 'CredentialAccept'
/** The subject of the credential. */
Account: string
/** The issuer of the credential. */
Issuer: string
/** A hex-encoded value to identify the type of credential from the issuer. */
CredentialType: string
}
/**
* Verify the form and type of a CredentialAccept at runtime.
*
* @param tx - A CredentialAccept Transaction.
* @throws When the CredentialAccept is Malformed.
*/
export function validateCredentialAccept(tx: Record<string, unknown>): void {
validateBaseTransaction(tx)
validateRequiredField(tx, 'Account', isString)
validateRequiredField(tx, 'Issuer', isString)
validateCredentialType(tx)
}

View File

@@ -0,0 +1,81 @@
import { HEX_REGEX } from '@xrplf/isomorphic/utils'
import { ValidationError } from '../../errors'
import {
BaseTransaction,
isNumber,
isString,
validateBaseTransaction,
validateCredentialType,
validateOptionalField,
validateRequiredField,
} from './common'
const MAX_URI_LENGTH = 256
/**
* Creates a Credential object. It must be sent by the issuer.
*
* @category Transaction Models
* */
export interface CredentialCreate extends BaseTransaction {
TransactionType: 'CredentialCreate'
/** The issuer of the credential. */
Account: string
/** The subject of the credential. */
Subject: string
/** A hex-encoded value to identify the type of credential from the issuer. */
CredentialType: string
/** Credential expiration. */
Expiration?: number
/** Additional data about the credential (such as a link to the VC document). */
URI?: string
}
/**
* Verify the form and type of a CredentialCreate at runtime.
*
* @param tx - A CredentialCreate Transaction.
* @throws When the CredentialCreate is Malformed.
*/
export function validateCredentialCreate(tx: Record<string, unknown>): void {
validateBaseTransaction(tx)
validateRequiredField(tx, 'Account', isString)
validateRequiredField(tx, 'Subject', isString)
validateCredentialType(tx)
validateOptionalField(tx, 'Expiration', isNumber)
validateURI(tx.URI)
}
function validateURI(URI: unknown): void {
if (URI === undefined) {
return
}
if (typeof URI !== 'string') {
throw new ValidationError('CredentialCreate: invalid field URI')
}
if (URI.length === 0) {
throw new ValidationError('CredentialCreate: URI cannot be an empty string')
} else if (URI.length > MAX_URI_LENGTH) {
throw new ValidationError(
`CredentialCreate: URI length must be <= ${MAX_URI_LENGTH}`,
)
}
if (!HEX_REGEX.test(URI)) {
throw new ValidationError('CredentialCreate: URI must be encoded in hex')
}
}

View File

@@ -0,0 +1,55 @@
import { ValidationError } from '../../errors'
import {
BaseTransaction,
isString,
validateBaseTransaction,
validateCredentialType,
validateOptionalField,
validateRequiredField,
} from './common'
/**
* Deletes a Credential object.
*
* @category Transaction Models
* */
export interface CredentialDelete extends BaseTransaction {
TransactionType: 'CredentialDelete'
/** The transaction submitter. */
Account: string
/** A hex-encoded value to identify the type of credential from the issuer. */
CredentialType: string
/** The person that the credential is for. If omitted, Account is assumed to be the subject. */
Subject?: string
/** The issuer of the credential. If omitted, Account is assumed to be the issuer. */
Issuer?: string
}
/**
* Verify the form and type of a CredentialDelete at runtime.
*
* @param tx - A CredentialDelete Transaction.
* @throws When the CredentialDelete is Malformed.
*/
export function validateCredentialDelete(tx: Record<string, unknown>): void {
validateBaseTransaction(tx)
if (!tx.Subject && !tx.Issuer) {
throw new ValidationError(
'CredentialDelete: either `Issuer` or `Subject` must be provided',
)
}
validateRequiredField(tx, 'Account', isString)
validateCredentialType(tx)
validateOptionalField(tx, 'Subject', isString)
validateOptionalField(tx, 'Issuer', isString)
}

View File

@@ -0,0 +1,67 @@
import {
BaseTransaction,
isString,
validateBaseTransaction,
validateRequiredField,
Account,
validateOptionalField,
isAccount,
GlobalFlags,
} from './common'
/**
* Transaction Flags for an MPTokenAuthorize Transaction.
*
* @category Transaction Flags
*/
export enum MPTokenAuthorizeFlags {
/**
* If set and transaction is submitted by a holder, it indicates that the holder no
* longer wants to hold the MPToken, which will be deleted as a result. If the the holder's
* MPToken has non-zero balance while trying to set this flag, the transaction will fail. On
* the other hand, if set and transaction is submitted by an issuer, it would mean that the
* issuer wants to unauthorize the holder (only applicable for allow-listing),
* which would unset the lsfMPTAuthorized flag on the MPToken.
*/
tfMPTUnauthorize = 0x00000001,
}
/**
* Map of flags to boolean values representing {@link MPTokenAuthorize} transaction
* flags.
*
* @category Transaction Flags
*/
export interface MPTokenAuthorizeFlagsInterface extends GlobalFlags {
tfMPTUnauthorize?: boolean
}
/**
* The MPTokenAuthorize transaction is used to globally lock/unlock a MPTokenIssuance,
* or lock/unlock an individual's MPToken.
*/
export interface MPTokenAuthorize extends BaseTransaction {
TransactionType: 'MPTokenAuthorize'
/**
* Identifies the MPTokenIssuance
*/
MPTokenIssuanceID: string
/**
* An optional XRPL Address of an individual token holder balance to lock/unlock.
* If omitted, this transaction will apply to all any accounts holding MPTs.
*/
Holder?: Account
Flags?: number | MPTokenAuthorizeFlagsInterface
}
/**
* Verify the form and type of an MPTokenAuthorize at runtime.
*
* @param tx - An MPTokenAuthorize Transaction.
* @throws When the MPTokenAuthorize is Malformed.
*/
export function validateMPTokenAuthorize(tx: Record<string, unknown>): void {
validateBaseTransaction(tx)
validateRequiredField(tx, 'MPTokenIssuanceID', isString)
validateOptionalField(tx, 'Holder', isAccount)
}

View File

@@ -0,0 +1,179 @@
import { ValidationError } from '../../errors'
import { isHex, INTEGER_SANITY_CHECK, isFlagEnabled } from '../utils'
import {
BaseTransaction,
GlobalFlags,
validateBaseTransaction,
validateOptionalField,
isString,
isNumber,
} from './common'
import type { TransactionMetadataBase } from './metadata'
// 2^63 - 1
const MAX_AMT = '9223372036854775807'
const MAX_TRANSFER_FEE = 50000
/**
* Transaction Flags for an MPTokenIssuanceCreate Transaction.
*
* @category Transaction Flags
*/
export enum MPTokenIssuanceCreateFlags {
/**
* If set, indicates that the MPT can be locked both individually and globally.
* If not set, the MPT cannot be locked in any way.
*/
tfMPTCanLock = 0x00000002,
/**
* If set, indicates that individual holders must be authorized.
* This enables issuers to limit who can hold their assets.
*/
tfMPTRequireAuth = 0x00000004,
/**
* If set, indicates that individual holders can place their balances into an escrow.
*/
tfMPTCanEscrow = 0x00000008,
/**
* If set, indicates that individual holders can trade their balances
* using the XRP Ledger DEX or AMM.
*/
tfMPTCanTrade = 0x00000010,
/**
* If set, indicates that tokens may be transferred to other accounts
* that are not the issuer.
*/
tfMPTCanTransfer = 0x00000020,
/**
* If set, indicates that the issuer may use the Clawback transaction
* to clawback value from individual holders.
*/
tfMPTCanClawback = 0x00000040,
}
/**
* Map of flags to boolean values representing {@link MPTokenIssuanceCreate} transaction
* flags.
*
* @category Transaction Flags
*/
export interface MPTokenIssuanceCreateFlagsInterface extends GlobalFlags {
tfMPTCanLock?: boolean
tfMPTRequireAuth?: boolean
tfMPTCanEscrow?: boolean
tfMPTCanTrade?: boolean
tfMPTCanTransfer?: boolean
tfMPTCanClawback?: boolean
}
/**
* The MPTokenIssuanceCreate transaction creates a MPTokenIssuance object
* and adds it to the relevant directory node of the creator account.
* This transaction is the only opportunity an issuer has to specify any token fields
* that are defined as immutable (e.g., MPT Flags). If the transaction is successful,
* the newly created token will be owned by the account (the creator account) which
* executed the transaction.
*/
export interface MPTokenIssuanceCreate extends BaseTransaction {
TransactionType: 'MPTokenIssuanceCreate'
/**
* An asset scale is the difference, in orders of magnitude, between a standard unit and
* a corresponding fractional unit. More formally, the asset scale is a non-negative integer
* (0, 1, 2, …) such that one standard unit equals 10^(-scale) of a corresponding
* fractional unit. If the fractional unit equals the standard unit, then the asset scale is 0.
* Note that this value is optional, and will default to 0 if not supplied.
*/
AssetScale?: number
/**
* Specifies the maximum asset amount of this token that should ever be issued.
* It is a non-negative integer string that can store a range of up to 63 bits. If not set, the max
* amount will default to the largest unsigned 63-bit integer (0x7FFFFFFFFFFFFFFF or 9223372036854775807)
*
* Example:
* ```
* MaximumAmount: '9223372036854775807'
* ```
*/
MaximumAmount?: string
/**
* Specifies the fee to charged by the issuer for secondary sales of the Token,
* if such sales are allowed. Valid values for this field are between 0 and 50,000 inclusive,
* allowing transfer rates of between 0.000% and 50.000% in increments of 0.001.
* The field must NOT be present if the `tfMPTCanTransfer` flag is not set.
*/
TransferFee?: number
/**
* Arbitrary metadata about this issuance, in hex format.
*/
MPTokenMetadata?: string | null
Flags?: number | MPTokenIssuanceCreateFlagsInterface
}
export interface MPTokenIssuanceCreateMetadata extends TransactionMetadataBase {
mpt_issuance_id?: string
}
/* eslint-disable max-lines-per-function -- Not needed to reduce function */
/**
* Verify the form and type of an MPTokenIssuanceCreate at runtime.
*
* @param tx - An MPTokenIssuanceCreate Transaction.
* @throws When the MPTokenIssuanceCreate is Malformed.
*/
export function validateMPTokenIssuanceCreate(
tx: Record<string, unknown>,
): void {
validateBaseTransaction(tx)
validateOptionalField(tx, 'MaximumAmount', isString)
validateOptionalField(tx, 'MPTokenMetadata', isString)
validateOptionalField(tx, 'TransferFee', isNumber)
validateOptionalField(tx, 'AssetScale', isNumber)
if (typeof tx.MPTokenMetadata === 'string' && tx.MPTokenMetadata === '') {
throw new ValidationError(
'MPTokenIssuanceCreate: MPTokenMetadata must not be empty string',
)
}
if (typeof tx.MPTokenMetadata === 'string' && !isHex(tx.MPTokenMetadata)) {
throw new ValidationError(
'MPTokenIssuanceCreate: MPTokenMetadata must be in hex format',
)
}
if (typeof tx.MaximumAmount === 'string') {
if (!INTEGER_SANITY_CHECK.exec(tx.MaximumAmount)) {
throw new ValidationError('MPTokenIssuanceCreate: Invalid MaximumAmount')
} else if (
BigInt(tx.MaximumAmount) > BigInt(MAX_AMT) ||
BigInt(tx.MaximumAmount) < BigInt(`0`)
) {
throw new ValidationError(
'MPTokenIssuanceCreate: MaximumAmount out of range',
)
}
}
if (typeof tx.TransferFee === 'number') {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Not necessary
const flags = tx.Flags as number | MPTokenIssuanceCreateFlagsInterface
const isTfMPTCanTransfer =
typeof flags === 'number'
? isFlagEnabled(flags, MPTokenIssuanceCreateFlags.tfMPTCanTransfer)
: flags.tfMPTCanTransfer ?? false
if (tx.TransferFee < 0 || tx.TransferFee > MAX_TRANSFER_FEE) {
throw new ValidationError(
`MPTokenIssuanceCreate: TransferFee must be between 0 and ${MAX_TRANSFER_FEE}`,
)
}
if (tx.TransferFee && !isTfMPTCanTransfer) {
throw new ValidationError(
'MPTokenIssuanceCreate: TransferFee cannot be provided without enabling tfMPTCanTransfer flag',
)
}
}
}
/* eslint-enable max-lines-per-function */

View File

@@ -0,0 +1,34 @@
import {
BaseTransaction,
isString,
validateBaseTransaction,
validateRequiredField,
} from './common'
/**
* The MPTokenIssuanceDestroy transaction is used to remove an MPTokenIssuance object
* from the directory node in which it is being held, effectively removing the token
* from the ledger. If this operation succeeds, the corresponding
* MPTokenIssuance is removed and the owners reserve requirement is reduced by one.
* This operation must fail if there are any holders who have non-zero balances.
*/
export interface MPTokenIssuanceDestroy extends BaseTransaction {
TransactionType: 'MPTokenIssuanceDestroy'
/**
* Identifies the MPTokenIssuance object to be removed by the transaction.
*/
MPTokenIssuanceID: string
}
/**
* Verify the form and type of an MPTokenIssuanceDestroy at runtime.
*
* @param tx - An MPTokenIssuanceDestroy Transaction.
* @throws When the MPTokenIssuanceDestroy is Malformed.
*/
export function validateMPTokenIssuanceDestroy(
tx: Record<string, unknown>,
): void {
validateBaseTransaction(tx)
validateRequiredField(tx, 'MPTokenIssuanceID', isString)
}

View File

@@ -0,0 +1,86 @@
import { ValidationError } from '../../errors'
import { isFlagEnabled } from '../utils'
import {
BaseTransaction,
isString,
validateBaseTransaction,
validateRequiredField,
Account,
validateOptionalField,
isAccount,
GlobalFlags,
} from './common'
/**
* Transaction Flags for an MPTokenIssuanceSet Transaction.
*
* @category Transaction Flags
*/
export enum MPTokenIssuanceSetFlags {
/**
* If set, indicates that issuer locks the MPT
*/
tfMPTLock = 0x00000001,
/**
* If set, indicates that issuer unlocks the MPT
*/
tfMPTUnlock = 0x00000002,
}
/**
* Map of flags to boolean values representing {@link MPTokenIssuanceSet} transaction
* flags.
*
* @category Transaction Flags
*/
export interface MPTokenIssuanceSetFlagsInterface extends GlobalFlags {
tfMPTLock?: boolean
tfMPTUnlock?: boolean
}
/**
* The MPTokenIssuanceSet transaction is used to globally lock/unlock a MPTokenIssuance,
* or lock/unlock an individual's MPToken.
*/
export interface MPTokenIssuanceSet extends BaseTransaction {
TransactionType: 'MPTokenIssuanceSet'
/**
* Identifies the MPTokenIssuance
*/
MPTokenIssuanceID: string
/**
* An optional XRPL Address of an individual token holder balance to lock/unlock.
* If omitted, this transaction will apply to all any accounts holding MPTs.
*/
Holder?: Account
Flags?: number | MPTokenIssuanceSetFlagsInterface
}
/**
* Verify the form and type of an MPTokenIssuanceSet at runtime.
*
* @param tx - An MPTokenIssuanceSet Transaction.
* @throws When the MPTokenIssuanceSet is Malformed.
*/
export function validateMPTokenIssuanceSet(tx: Record<string, unknown>): void {
validateBaseTransaction(tx)
validateRequiredField(tx, 'MPTokenIssuanceID', isString)
validateOptionalField(tx, 'Holder', isAccount)
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Not necessary
const flags = tx.Flags as number | MPTokenIssuanceSetFlagsInterface
const isTfMPTLock =
typeof flags === 'number'
? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTLock)
: flags.tfMPTLock ?? false
const isTfMPTUnlock =
typeof flags === 'number'
? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTUnlock)
: flags.tfMPTUnlock ?? false
if (isTfMPTLock && isTfMPTUnlock) {
throw new ValidationError('MPTokenIssuanceSet: flag conflict')
}
}

View File

@@ -4,6 +4,7 @@ import {
isAccount, isAccount,
isNumber, isNumber,
validateBaseTransaction, validateBaseTransaction,
validateCredentialsList,
validateOptionalField, validateOptionalField,
validateRequiredField, validateRequiredField,
} from './common' } from './common'
@@ -28,6 +29,12 @@ export interface AccountDelete extends BaseTransaction {
* information for the recipient of the deleted account's leftover XRP. * information for the recipient of the deleted account's leftover XRP.
*/ */
DestinationTag?: number DestinationTag?: number
/**
* Credentials associated with sender of this transaction. The credentials included
* must not be expired. The list must not be empty when specified and cannot contain
* more than 8 credentials.
*/
CredentialIDs?: string[]
} }
/** /**
@@ -41,4 +48,11 @@ export function validateAccountDelete(tx: Record<string, unknown>): void {
validateRequiredField(tx, 'Destination', isAccount) validateRequiredField(tx, 'Destination', isAccount)
validateOptionalField(tx, 'DestinationTag', isNumber) validateOptionalField(tx, 'DestinationTag', isNumber)
validateCredentialsList(
tx.CredentialIDs,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
tx.TransactionType as string,
true,
)
} }

View File

@@ -1,10 +1,13 @@
import { ValidationError } from '../../errors' import { ValidationError } from '../../errors'
import { IssuedCurrencyAmount } from '../common' import { IssuedCurrencyAmount, MPTAmount } from '../common'
import { import {
BaseTransaction, BaseTransaction,
validateBaseTransaction, validateBaseTransaction,
isIssuedCurrency, isIssuedCurrency,
isMPTAmount,
isAccount,
validateOptionalField,
} from './common' } from './common'
/** /**
@@ -15,15 +18,20 @@ export interface Clawback extends BaseTransaction {
TransactionType: 'Clawback' TransactionType: 'Clawback'
/** /**
* Indicates the AccountID that submitted this transaction. The account MUST * Indicates the AccountID that submitted this transaction. The account MUST
* be the issuer of the currency. * be the issuer of the currency or MPT.
*/ */
Account: string Account: string
/** /**
* The amount of currency to deliver, and it must be non-XRP. The nested field * The amount of currency or MPT to clawback, and it must be non-XRP. The nested field
* names MUST be lower-case. The `issuer` field MUST be the holder's address, * names MUST be lower-case. If the amount is IOU, the `issuer` field MUST be the holder's address,
* whom to be clawed back. * whom to be clawed back.
*/ */
Amount: IssuedCurrencyAmount Amount: IssuedCurrencyAmount | MPTAmount
/**
* Indicates the AccountID that the issuer wants to clawback. This field is only valid for clawing back
* MPTs.
*/
Holder?: string
} }
/** /**
@@ -34,16 +42,29 @@ export interface Clawback extends BaseTransaction {
*/ */
export function validateClawback(tx: Record<string, unknown>): void { export function validateClawback(tx: Record<string, unknown>): void {
validateBaseTransaction(tx) validateBaseTransaction(tx)
validateOptionalField(tx, 'Holder', isAccount)
if (tx.Amount == null) { if (tx.Amount == null) {
throw new ValidationError('Clawback: missing field Amount') throw new ValidationError('Clawback: missing field Amount')
} }
if (!isIssuedCurrency(tx.Amount)) { if (!isIssuedCurrency(tx.Amount) && !isMPTAmount(tx.Amount)) {
throw new ValidationError('Clawback: invalid Amount') throw new ValidationError('Clawback: invalid Amount')
} }
if (isIssuedCurrency(tx.Amount) && tx.Account === tx.Amount.issuer) { if (isIssuedCurrency(tx.Amount) && tx.Account === tx.Amount.issuer) {
throw new ValidationError('Clawback: invalid holder Account') throw new ValidationError('Clawback: invalid holder Account')
} }
if (isMPTAmount(tx.Amount) && tx.Account === tx.Holder) {
throw new ValidationError('Clawback: invalid holder Account')
}
if (isIssuedCurrency(tx.Amount) && tx.Holder) {
throw new ValidationError('Clawback: cannot have Holder for currency')
}
if (isMPTAmount(tx.Amount) && !tx.Holder) {
throw new ValidationError('Clawback: missing Holder')
}
} }

View File

@@ -1,18 +1,25 @@
/* eslint-disable max-lines -- common utility file */
import { HEX_REGEX } from '@xrplf/isomorphic/utils'
import { isValidClassicAddress, isValidXAddress } from 'ripple-address-codec' import { isValidClassicAddress, isValidXAddress } from 'ripple-address-codec'
import { TRANSACTION_TYPES } from 'ripple-binary-codec' import { TRANSACTION_TYPES } from 'ripple-binary-codec'
import { ValidationError } from '../../errors' import { ValidationError } from '../../errors'
import { import {
Amount, Amount,
AuthorizeCredential,
Currency, Currency,
IssuedCurrencyAmount, IssuedCurrencyAmount,
Memo, Memo,
Signer, Signer,
XChainBridge, XChainBridge,
MPTAmount,
} from '../common' } from '../common'
import { onlyHasFields } from '../utils' import { onlyHasFields } from '../utils'
const MEMO_SIZE = 3 const MEMO_SIZE = 3
const MAX_CREDENTIALS_LIST_LENGTH = 8
const MAX_CREDENTIAL_BYTE_LENGTH = 64
const MAX_CREDENTIAL_TYPE_LENGTH = MAX_CREDENTIAL_BYTE_LENGTH * 2
function isMemo(obj: { Memo?: unknown }): boolean { function isMemo(obj: { Memo?: unknown }): boolean {
if (obj.Memo == null) { if (obj.Memo == null) {
@@ -59,6 +66,8 @@ const XRP_CURRENCY_SIZE = 1
const ISSUE_SIZE = 2 const ISSUE_SIZE = 2
const ISSUED_CURRENCY_SIZE = 3 const ISSUED_CURRENCY_SIZE = 3
const XCHAIN_BRIDGE_SIZE = 4 const XCHAIN_BRIDGE_SIZE = 4
const MPTOKEN_SIZE = 2
const AUTHORIZE_CREDENTIAL_SIZE = 1
function isRecord(value: unknown): value is Record<string, unknown> { function isRecord(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === 'object' return value !== null && typeof value === 'object'
@@ -119,6 +128,37 @@ export function isIssuedCurrency(
) )
} }
/**
* Verify the form and type of an AuthorizeCredential at runtime
*
* @param input - The input to check the form and type of
* @returns Whether the AuthorizeCredential is properly formed
*/
function isAuthorizeCredential(input: unknown): input is AuthorizeCredential {
return (
isRecord(input) &&
isRecord(input.Credential) &&
Object.keys(input).length === AUTHORIZE_CREDENTIAL_SIZE &&
typeof input.Credential.CredentialType === 'string' &&
typeof input.Credential.Issuer === 'string'
)
}
/**
* Verify the form and type of an MPT at runtime.
*
* @param input - The input to check the form and type of.
* @returns Whether the MPTAmount is properly formed.
*/
export function isMPTAmount(input: unknown): input is MPTAmount {
return (
isRecord(input) &&
Object.keys(input).length === MPTOKEN_SIZE &&
typeof input.value === 'string' &&
typeof input.mpt_issuance_id === 'string'
)
}
/** /**
* Must be a valid account address * Must be a valid account address
*/ */
@@ -144,7 +184,11 @@ export function isAccount(account: unknown): account is Account {
* @returns Whether the Amount is properly formed. * @returns Whether the Amount is properly formed.
*/ */
export function isAmount(amount: unknown): amount is Amount { export function isAmount(amount: unknown): amount is Amount {
return typeof amount === 'string' || isIssuedCurrency(amount) return (
typeof amount === 'string' ||
isIssuedCurrency(amount) ||
isMPTAmount(amount)
)
} }
/** /**
@@ -366,3 +410,97 @@ export function parseAmountValue(amount: unknown): number {
} }
return parseFloat(amount.value) return parseFloat(amount.value)
} }
/**
* Verify the form and type of a CredentialType at runtime.
*
* @param tx A CredentialType Transaction.
* @throws when the CredentialType is malformed.
*/
export function validateCredentialType(tx: Record<string, unknown>): void {
if (typeof tx.TransactionType !== 'string') {
throw new ValidationError('Invalid TransactionType')
}
if (tx.CredentialType === undefined) {
throw new ValidationError(
`${tx.TransactionType}: missing field CredentialType`,
)
}
if (!isString(tx.CredentialType)) {
throw new ValidationError(
`${tx.TransactionType}: CredentialType must be a string`,
)
}
if (tx.CredentialType.length === 0) {
throw new ValidationError(
`${tx.TransactionType}: CredentialType cannot be an empty string`,
)
} else if (tx.CredentialType.length > MAX_CREDENTIAL_TYPE_LENGTH) {
throw new ValidationError(
`${tx.TransactionType}: CredentialType length cannot be > ${MAX_CREDENTIAL_TYPE_LENGTH}`,
)
}
if (!HEX_REGEX.test(tx.CredentialType)) {
throw new ValidationError(
`${tx.TransactionType}: CredentialType must be encoded in hex`,
)
}
}
/**
* Check a CredentialAuthorize array for parameter errors
*
* @param credentials An array of credential IDs to check for errors
* @param transactionType The transaction type to include in error messages
* @param isStringID Toggle for if array contains IDs instead of AuthorizeCredential objects
* @throws Validation Error if the formatting is incorrect
*/
// eslint-disable-next-line max-lines-per-function -- separating logic further will add unnecessary complexity
export function validateCredentialsList(
credentials: unknown,
transactionType: string,
isStringID: boolean,
): void {
if (credentials == null) {
return
}
if (!Array.isArray(credentials)) {
throw new ValidationError(
`${transactionType}: Credentials must be an array`,
)
}
if (credentials.length > MAX_CREDENTIALS_LIST_LENGTH) {
throw new ValidationError(
`${transactionType}: Credentials length cannot exceed ${MAX_CREDENTIALS_LIST_LENGTH} elements`,
)
} else if (credentials.length === 0) {
throw new ValidationError(
`${transactionType}: Credentials cannot be an empty array`,
)
}
credentials.forEach((credential) => {
if (isStringID) {
if (!isString(credential)) {
throw new ValidationError(
`${transactionType}: Invalid Credentials ID list format`,
)
}
} else if (!isAuthorizeCredential(credential)) {
throw new ValidationError(
`${transactionType}: Invalid Credentials format`,
)
}
})
if (containsDuplicates(credentials)) {
throw new ValidationError(
`${transactionType}: Credentials cannot contain duplicate elements`,
)
}
}
function containsDuplicates(objectList: object[]): boolean {
const objSet = new Set(objectList.map((obj) => JSON.stringify(obj)))
return objSet.size !== objectList.length
}

View File

@@ -1,6 +1,11 @@
import { ValidationError } from '../../errors' import { ValidationError } from '../../errors'
import { AuthorizeCredential } from '../common'
import { BaseTransaction, validateBaseTransaction } from './common' import {
BaseTransaction,
validateBaseTransaction,
validateCredentialsList,
} from './common'
/** /**
* A DepositPreauth transaction gives another account pre-approval to deliver * A DepositPreauth transaction gives another account pre-approval to deliver
@@ -18,6 +23,16 @@ export interface DepositPreauth extends BaseTransaction {
* revoked. * revoked.
*/ */
Unauthorize?: string Unauthorize?: string
/**
* The credential(s) to preauthorize.
*/
AuthorizeCredentials?: AuthorizeCredential[]
/**
* The credential(s) whose preauthorization should be revoked.
*/
UnauthorizeCredentials?: AuthorizeCredential[]
} }
/** /**
@@ -29,17 +44,7 @@ export interface DepositPreauth extends BaseTransaction {
export function validateDepositPreauth(tx: Record<string, unknown>): void { export function validateDepositPreauth(tx: Record<string, unknown>): void {
validateBaseTransaction(tx) validateBaseTransaction(tx)
if (tx.Authorize !== undefined && tx.Unauthorize !== undefined) { validateSingleAuthorizationFieldProvided(tx)
throw new ValidationError(
"DepositPreauth: can't provide both Authorize and Unauthorize fields",
)
}
if (tx.Authorize === undefined && tx.Unauthorize === undefined) {
throw new ValidationError(
'DepositPreauth: must provide either Authorize or Unauthorize field',
)
}
if (tx.Authorize !== undefined) { if (tx.Authorize !== undefined) {
if (typeof tx.Authorize !== 'string') { if (typeof tx.Authorize !== 'string') {
@@ -51,9 +56,7 @@ export function validateDepositPreauth(tx: Record<string, unknown>): void {
"DepositPreauth: Account can't preauthorize its own address", "DepositPreauth: Account can't preauthorize its own address",
) )
} }
} } else if (tx.Unauthorize !== undefined) {
if (tx.Unauthorize !== undefined) {
if (typeof tx.Unauthorize !== 'string') { if (typeof tx.Unauthorize !== 'string') {
throw new ValidationError('DepositPreauth: Unauthorize must be a string') throw new ValidationError('DepositPreauth: Unauthorize must be a string')
} }
@@ -63,5 +66,38 @@ export function validateDepositPreauth(tx: Record<string, unknown>): void {
"DepositPreauth: Account can't unauthorize its own address", "DepositPreauth: Account can't unauthorize its own address",
) )
} }
} else if (tx.AuthorizeCredentials !== undefined) {
validateCredentialsList(
tx.AuthorizeCredentials,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check
tx.TransactionType as string,
false,
)
} else if (tx.UnauthorizeCredentials !== undefined) {
validateCredentialsList(
tx.UnauthorizeCredentials,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check
tx.TransactionType as string,
false,
)
}
}
// Boolean logic to ensure exactly one of 4 inputs was provided
function validateSingleAuthorizationFieldProvided(
tx: Record<string, unknown>,
): void {
const fields = [
'Authorize',
'Unauthorize',
'AuthorizeCredentials',
'UnauthorizeCredentials',
]
const countProvided = fields.filter((key) => tx[key] !== undefined).length
if (countProvided !== 1) {
throw new ValidationError(
'DepositPreauth: Requires exactly one field of the following: Authorize, Unauthorize, AuthorizeCredentials, UnauthorizeCredentials.',
)
} }
} }

View File

@@ -5,6 +5,7 @@ import {
BaseTransaction, BaseTransaction,
isAccount, isAccount,
validateBaseTransaction, validateBaseTransaction,
validateCredentialsList,
validateRequiredField, validateRequiredField,
} from './common' } from './common'
@@ -32,6 +33,10 @@ export interface EscrowFinish extends BaseTransaction {
* the held payment's Condition. * the held payment's Condition.
*/ */
Fulfillment?: string Fulfillment?: string
/** Credentials associated with the sender of this transaction.
* The credentials included must not be expired.
*/
CredentialIDs?: string[]
} }
/** /**
@@ -45,6 +50,13 @@ export function validateEscrowFinish(tx: Record<string, unknown>): void {
validateRequiredField(tx, 'Owner', isAccount) validateRequiredField(tx, 'Owner', isAccount)
validateCredentialsList(
tx.CredentialIDs,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
tx.TransactionType as string,
true,
)
if (tx.OfferSequence == null) { if (tx.OfferSequence == null) {
throw new ValidationError('EscrowFinish: missing field OfferSequence') throw new ValidationError('EscrowFinish: missing field OfferSequence')
} }

View File

@@ -1,4 +1,4 @@
export { BaseTransaction } from './common' export { BaseTransaction, isMPTAmount } from './common'
export { export {
validate, validate,
PseudoTransaction, PseudoTransaction,
@@ -32,6 +32,9 @@ export { CheckCancel } from './checkCancel'
export { CheckCash } from './checkCash' export { CheckCash } from './checkCash'
export { CheckCreate } from './checkCreate' export { CheckCreate } from './checkCreate'
export { Clawback } from './clawback' export { Clawback } from './clawback'
export { CredentialAccept } from './CredentialAccept'
export { CredentialCreate } from './CredentialCreate'
export { CredentialDelete } from './CredentialDelete'
export { DIDDelete } from './DIDDelete' export { DIDDelete } from './DIDDelete'
export { DIDSet } from './DIDSet' export { DIDSet } from './DIDSet'
export { DepositPreauth } from './depositPreauth' export { DepositPreauth } from './depositPreauth'
@@ -39,6 +42,22 @@ export { EscrowCancel } from './escrowCancel'
export { EscrowCreate } from './escrowCreate' export { EscrowCreate } from './escrowCreate'
export { EscrowFinish } from './escrowFinish' export { EscrowFinish } from './escrowFinish'
export { EnableAmendment, EnableAmendmentFlags } from './enableAmendment' export { EnableAmendment, EnableAmendmentFlags } from './enableAmendment'
export {
MPTokenAuthorize,
MPTokenAuthorizeFlags,
MPTokenAuthorizeFlagsInterface,
} from './MPTokenAuthorize'
export {
MPTokenIssuanceCreate,
MPTokenIssuanceCreateFlags,
MPTokenIssuanceCreateFlagsInterface,
} from './MPTokenIssuanceCreate'
export { MPTokenIssuanceDestroy } from './MPTokenIssuanceDestroy'
export {
MPTokenIssuanceSet,
MPTokenIssuanceSetFlags,
MPTokenIssuanceSetFlagsInterface,
} from './MPTokenIssuanceSet'
export { NFTokenAcceptOffer } from './NFTokenAcceptOffer' export { NFTokenAcceptOffer } from './NFTokenAcceptOffer'
export { NFTokenBurn } from './NFTokenBurn' export { NFTokenBurn } from './NFTokenBurn'
export { NFTokenCancelOffer } from './NFTokenCancelOffer' export { NFTokenCancelOffer } from './NFTokenCancelOffer'
@@ -58,6 +77,8 @@ export {
OfferCreateFlagsInterface, OfferCreateFlagsInterface,
OfferCreate, OfferCreate,
} from './offerCreate' } from './offerCreate'
export { OracleDelete } from './oracleDelete'
export { OracleSet } from './oracleSet'
export { PaymentFlags, PaymentFlagsInterface, Payment } from './payment' export { PaymentFlags, PaymentFlagsInterface, Payment } from './payment'
export { export {
PaymentChannelClaimFlags, PaymentChannelClaimFlags,

View File

@@ -1,6 +1,10 @@
import { Amount } from '../common' import { Amount, MPTAmount } from '../common'
import { BaseTransaction } from './common' import { BaseTransaction } from './common'
import {
MPTokenIssuanceCreate,
MPTokenIssuanceCreateMetadata,
} from './MPTokenIssuanceCreate'
import { import {
NFTokenAcceptOffer, NFTokenAcceptOffer,
NFTokenAcceptOfferMetadata, NFTokenAcceptOfferMetadata,
@@ -40,6 +44,7 @@ export interface DeletedNode {
DeletedNode: { DeletedNode: {
LedgerEntryType: string LedgerEntryType: string
LedgerIndex: string LedgerIndex: string
PreviousFields?: { [field: string]: unknown }
FinalFields: { [field: string]: unknown } FinalFields: { [field: string]: unknown }
} }
} }
@@ -78,9 +83,9 @@ export function isDeletedNode(node: Node): node is DeletedNode {
export interface TransactionMetadataBase { export interface TransactionMetadataBase {
AffectedNodes: Node[] AffectedNodes: Node[]
DeliveredAmount?: Amount DeliveredAmount?: Amount | MPTAmount
// "unavailable" possible for transactions before 2014-01-20 // "unavailable" possible for transactions before 2014-01-20
delivered_amount?: Amount | 'unavailable' delivered_amount?: Amount | MPTAmount | 'unavailable'
TransactionIndex: number TransactionIndex: number
TransactionResult: string TransactionResult: string
} }
@@ -96,4 +101,6 @@ export type TransactionMetadata<T extends BaseTransaction = Transaction> =
? NFTokenAcceptOfferMetadata ? NFTokenAcceptOfferMetadata
: T extends NFTokenCancelOffer : T extends NFTokenCancelOffer
? NFTokenCancelOfferMetadata ? NFTokenCancelOfferMetadata
: T extends MPTokenIssuanceCreate
? MPTokenIssuanceCreateMetadata
: TransactionMetadataBase : TransactionMetadataBase

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)
}

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