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

View File

@@ -4,7 +4,7 @@
name: Node.js CI
env:
RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.0.0-b4
RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.3.0-rc1
on:
push:
@@ -19,22 +19,22 @@ jobs:
strategy:
matrix:
node-version: [16.x]
node-version: [18.x]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Setup npm version 9
- name: Setup npm version 10
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
id: cache-nodemodules
uses: actions/cache@v3
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
@@ -45,7 +45,6 @@ jobs:
key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-deps-${{ matrix.node-version }}-
${{ runner.os }}-deps-
- name: Install Dependencies
if: steps.cache-nodemodules.outputs.cache-hit != 'true'
@@ -60,22 +59,22 @@ jobs:
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
node-version: [18.x, 20.x, 22.x]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Setup npm version 9
- name: Setup npm version 10
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
id: cache-nodemodules
uses: actions/cache@v3
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
@@ -86,7 +85,6 @@ jobs:
key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-deps-${{ matrix.node-version }}-
${{ runner.os }}-deps-
- name: Install Dependencies
if: steps.cache-nodemodules.outputs.cache-hit != 'true'
@@ -101,27 +99,27 @@ jobs:
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
node-version: [18.x, 20.x, 22.x]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Run docker in background
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 }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Setup npm version 9
- name: Setup npm version 10
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
id: cache-nodemodules
uses: actions/cache@v3
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
@@ -132,7 +130,6 @@ jobs:
key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-deps-${{ matrix.node-version }}-
${{ runner.os }}-deps-
- name: Install Dependencies
if: steps.cache-nodemodules.outputs.cache-hit != 'true'
@@ -153,27 +150,27 @@ jobs:
strategy:
matrix:
node-version: [16.x]
node-version: [18.x]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Run docker in background
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: |
npm i -g npm@9 --registry=https://registry.npmjs.org
npm i -g npm@10 --registry=https://registry.npmjs.org
- name: Cache node modules
id: cache-nodemodules
uses: actions/cache@v3
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
@@ -184,7 +181,6 @@ jobs:
key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-deps-${{ matrix.node-version }}-
${{ runner.os }}-deps-
- name: Install Dependencies
if: steps.cache-nodemodules.outputs.cache-hit != 'true'
@@ -205,22 +201,22 @@ jobs:
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
node-version: [18.x, 20.x, 22.x]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Setup npm version 9
- name: Setup npm version 10
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
id: cache-nodemodules
uses: actions/cache@v3
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
@@ -231,7 +227,6 @@ jobs:
key: ${{ runner.os }}-deps-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-deps-${{ matrix.node-version }}-
${{ runner.os }}-deps-
- name: Install Dependencies
if: steps.cache-nodemodules.outputs.cache-hit != 'true'

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,6 +2,19 @@
## 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)
### 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.
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 2.0.0 Beta 1 (2023-11-30)
### Breaking Changes
* `Buffer` has been replaced with `UInt8Array` for both params and return values. `Buffer` may continue to work with params since they extend `UInt8Arrays`.
### Changes
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 2.0.0 Beta 0 (2023-10-19)
### Breaking Changes
* Bump typescript to 5.x
* Remove Node 14 support
* Remove decimal.js and big-integer. Use `BigNumber` from `bignumber.js` instead of `Decimal` and the native `BigInt` instead of `bigInt`.
* Remove `assert` dependency. If you were catching `AssertionError` you need to change to `Error`.
* Remove `create-hash` in favor of `@noble/hashes`
### Changes
* Update type definitions which causing errors in tests that the code already supported
* `makeParser` to accept a `Buffer` in addition to `string`

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -6,6 +6,7 @@ import { JsonObject, SerializedType } from './serialized-type'
import BigNumber from 'bignumber.js'
import { bytesToHex, concat, hexToBytes } from '@xrplf/isomorphic/utils'
import { readUInt32BE, writeUInt32BE } from '../utils'
import { Hash192 } from './hash-192'
/**
* Constants for validating amounts
@@ -16,6 +17,7 @@ const MAX_IOU_PRECISION = 16
const MAX_DROPS = new BigNumber('1e17')
const MIN_XRP = new BigNumber('1e-6')
const mask = BigInt(0x00000000ffffffff)
const mptMask = BigInt(0x8000000000000000)
/**
* BigNumber configuration for Amount IOUs
@@ -27,20 +29,28 @@ BigNumber.config({
],
})
/**
* Interface for JSON objects that represent amounts
*/
interface AmountObject extends JsonObject {
interface AmountObjectIOU extends JsonObject {
value: string
currency: 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()
return (
keys.length === 3 &&
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
*/
@@ -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
* representing an integer amount
@@ -88,7 +109,7 @@ class Amount extends SerializedType {
return new Amount(amount)
}
if (isAmountObject(value)) {
if (isAmountObjectIOU(value)) {
const number = new BigNumber(value.value)
Amount.assertIouIsValid(number)
@@ -124,6 +145,24 @@ class Amount extends SerializedType {
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')
}
@@ -134,8 +173,12 @@ class Amount extends SerializedType {
* @returns An Amount object
*/
static fromParser(parser: BinaryParser): Amount {
const isXRP = parser.peek() & 0x80
const numBytes = isXRP ? 48 : 8
const isIOU = parser.peek() & 0x80
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))
}
@@ -156,7 +199,9 @@ class Amount extends SerializedType {
const num = (msb << BigInt(32)) | lsb
return `${sign}${num.toString()}`
} else {
}
if (this.isIOU()) {
const parser = new BinaryParser(this.toString())
const mantissa = parser.read(8)
const currency = Currency.fromParser(parser) as Currency
@@ -182,6 +227,27 @@ class Amount extends SerializedType {
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
* contain a decimal.
@@ -248,7 +337,25 @@ class Amount extends SerializedType {
* @returns true if Native (XRP)
*/
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 (!/^[A-F0-9]*$/iu.test(value)) {
throw new Error('Cannot construct Blob from a non-hex string')
}
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 { Hash128 } from './hash-128'
import { Hash160 } from './hash-160'
import { Hash192 } from './hash-192'
import { Hash256 } from './hash-256'
import { Issue } from './issue'
import { PathSet } from './path-set'
@@ -25,6 +26,7 @@ const coreTypes: Record<string, typeof SerializedType> = {
Currency,
Hash128,
Hash160,
Hash192,
Hash256,
Issue,
PathSet,
@@ -51,6 +53,7 @@ export {
Currency,
Hash128,
Hash160,
Hash192,
Hash256,
PathSet,
STArray,

View File

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

View File

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

View File

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

View File

@@ -2,10 +2,20 @@ import { UInt } from './uint'
import { BinaryParser } from '../serdes/binary-parser'
import { bytesToHex, concat, hexToBytes } from '@xrplf/isomorphic/utils'
import { readUInt32BE, writeUInt32BE } from '../utils'
import { DEFAULT_DEFINITIONS, XrplDefinitionsBase } from '../enums'
const HEX_REGEX = /^[a-fA-F0-9]{1,16}$/
const BASE10_REGEX = /^[0-9]{1,20}$/
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
*/
@@ -29,7 +39,10 @@ class UInt64 extends UInt {
* @param val A UInt64, hex-string, bigInt, or number
* @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) {
return val
}
@@ -51,11 +64,18 @@ class UInt64 extends UInt {
}
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`)
}
const strBuf = val.padStart(16, '0')
const strBuf = (val as string).padStart(16, '0')
buf = hexToBytes(strBuf)
return new UInt64(buf)
}
@@ -76,8 +96,16 @@ class UInt64 extends UInt {
*
* @returns a hex-string
*/
toJSON(): string {
return bytesToHex(this.bytes)
toJSON(
_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 fixtures from './fixtures/data-driven-tests.json'
import { makeParser } from '../src/binary'
const { Amount } = coreTypes
function amountErrorTests() {
@@ -25,6 +27,16 @@ describe('Amount', function () {
it('can be parsed from', function () {
expect(Amount.from('1000000') instanceof Amount).toBe(true)
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 = {
value: '1',
issuer: '0000000000000000000000000000000000000000',
@@ -38,5 +50,35 @@ describe('Amount', function () {
}
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()
})

View File

@@ -22,6 +22,7 @@ function assertEqualAmountJSON(actual, expected) {
}
expect(actual.currency).toEqual(expected.currency)
expect(actual.issuer).toEqual(expected.issuer)
expect(actual.mpt_issuance_id).toEqual(expected.mpt_issuance_id)
expect(
actual.value === expected.value ||
new BigNumber(actual.value).eq(new BigNumber(expected.value)),
@@ -207,12 +208,12 @@ function amountParsingTests() {
return
}
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,
16,
)}...
as ${JSON.stringify(f.test_json)}`
it(testName, () => {
it(hexToJsonTestName, () => {
const value = parser.readType(Amount)
// May not actually be in canonical form. The fixtures are to be used
// also for json -> binary;
@@ -223,6 +224,15 @@ function amountParsingTests() {
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', () => {
const parser = makeParser('0101')
expect(() => parser.readField()).toThrow(
new Error('Cannot read FieldOrdinal, type_code out of range'),
new Error('Cannot read FieldOrdinal, type_code 1 out of range'),
)
})
it('Field throws when field code out of range', () => {
const parser = makeParser('1001')
expect(() => parser.readFieldOrdinal()).toThrow(
new Error('Cannot read FieldOrdinal, field_code out of range'),
new Error('Cannot read FieldOrdinal, field_code 1 out of range'),
)
})
it('Field throws when both type and field code out of range', () => {
const parser = makeParser('000101')
expect(() => parser.readFieldOrdinal()).toThrow(
new Error('Cannot read FieldOrdinal, type_code out of range'),
new Error('Cannot read FieldOrdinal, type_code 1 out of range'),
)
})
it('readUIntN', () => {

View File

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

View File

@@ -2499,7 +2499,7 @@
"type_id": 6,
"is_native": true,
"type": "Amount",
"expected_hex": "0000000000000001",
"error": "Value is negative",
"is_negative": true
},
{
@@ -2914,6 +2914,170 @@
"type": "Amount",
"error": "10000000000000000000 absolute XRP is bigger than max native value 100000000000.0",
"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 () {
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 () {
it('has a static width member', function () {
expect(Hash256.width).toBe(32)

View File

@@ -73,7 +73,9 @@ describe('Signing data', function () {
const customPaymentDefinitions = JSON.parse(
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 actual = encodeForSigning(tx_json, newDefs)
@@ -82,7 +84,7 @@ describe('Signing data', function () {
'53545800', // signingPrefix
// TransactionType
'12',
'001F',
'00C8',
// Flags
'22',
'80000000',
@@ -176,7 +178,9 @@ describe('Signing data', function () {
const customPaymentDefinitions = JSON.parse(
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 signingAccount = 'rJZdUusLDtY9NEsGea7ijqhVrXv98rYBYN'
@@ -187,7 +191,7 @@ describe('Signing data', function () {
'534D5400', // signingPrefix
// TransactionType
'12',
'001F',
'00C8',
// Flags
'22',
'80000000',

View File

@@ -1,5 +1,5 @@
import { UInt8, UInt64 } from '../src/types'
import { encode } from '../src'
import { encode, decode } from '../src'
const binary =
'11007222000300003700000000000000003800000000000000006280000000000000000000000000000000000000005553440000000000000000000000000000000000000000000000000166D5438D7EA4C680000000000000000000000000005553440000000000AE123A8556F3CF91154711376AFB0F894F832B3D67D5438D7EA4C680000000000000000000000000005553440000000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B90F'
@@ -96,6 +96,40 @@ const jsonEntry2 = {
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]', () => {
expect(UInt8.from(124).compareTo(UInt64.from(124))).toBe(0)
})
@@ -144,3 +178,20 @@ it('valueOf tests', () => {
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.
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 2.0.0 Beta 1 (2023-11-30)
### Breaking Changes
* `Buffer` has been replaced with `UInt8Array` for both params and return values. `Buffer` may continue to work with params since they extend `UInt8Arrays`.
### Changes
* Eliminates 4 runtime dependencies: `base-x`, `base64-js`, `buffer`, and `ieee754`.
## 2.0.0 Beta 0 (2023-10-19)
### Breaking Changes
* Bump typescript to 5.x
* Remove Node 14 support
* Remove `assert` dependency. If you were catching `AssertionError` you need to change to `Error`.
* Fix `deriveKeypair` ignoring manual decoding algorithm. (Specifying algorithm=`ed25519` in `opts` now works on secrets like `sNa1...`)
* Remove `crypto` polyfills, `create-hash`, `elliptic`, `hash.js`, and their many dependencies in favor of `@noble/hashes` and `@nobel/curves`
* Remove `bytesToHex` and `hexToBytes`. They can now be found in `@xrplf/isomorphic/utils`
* `verifyTransaction` will throw an error if there is no signature
* Improved key algorithm detection. It will now throw Errors with helpful messages
### Changes
* Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead.
## 1.3.1 (2023-09-27)
### Fixed
* Fix source-maps not finding their designated source

View File

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

View File

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

View File

@@ -2,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.
## 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)
### BREAKING CHANGES
* The default signing algorithm in the `Wallet` was changed from secp256k1 to ed25519
* 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`
@@ -52,80 +98,6 @@ Bundler configurations are much more simplified. See [../UNIQUE_STEPS](Unique St
* Deprecated:
* `convertHexToString` in favor of `@xrplf/isomorphic/utils`'s `hexToString`
* `convertStringToHex` in favor of `@xrplf/isomorphic/utils`'s `stringToHex`
## 3.0.0 Beta 1 (2023-11-30)
### Breaking Changes
* `Transaction` type has been redefined to include all transactions and `SubmittableTransaction` was created to define the old value. The following functions which only handle transactions to be submitted now use `SubmittableTransaction`:
* `Client.autofill`
* `Client.submit`
* `Client.submitAndWait`
* `Client.prepareTransaction`
* `getSignedTx`
* `isAccountDelete`
* `dropsToXRP` and `Client.getXrpBalance` now return a `number` instead of a `string`
* `Buffer` has been replaced with `UInt8Array` for both params and return values. `Buffer` may continue to work with params since they extend `UInt8Arrays`.
### Bundling Changes
* `Buffer` and `process` polyfills are no longer required.
### Changes
* Deprecated:
* `convertHexToString` in favor of `@xrplf/isomorphic/utils`'s `hexToString`
* `convertStringToHex` in favor of `@xrplf/isomorphic/utils`'s `stringToHex`
* Remove `lodash` as a dependency
* Remove many polyfills that were only used for testing in the browser
* Remove `util` from bundle by switching `inspect` to `JSON.stringify`
* Add type for metadata for specific transactions(`Payment`, `NFTokenMint`, `NFTokenCreateOffer`, `NFTokenAcceptOffer`, `NFTokenCancelOffer`)
### Fixed
* Fixed Wallet.generate() ignoring the `algorithm` parameter (Only a problem once binary-codec fix for `derive_keypair` is added)
* Fixed Wallet.fromSeed() ignoring the `algorithm` parameter
* Added pseudo-transaction support to hash functions and response types
## 3.0.0 Beta 0 (2023-10-19)
### Breaking Changes
* Bump typescript to 5.x
* Remove Node 14 support
* Remove `crypto` polyfills, `create-hash`, `elliptic`, `hash.js`, and their many dependencies in favor of `@noble/hashes` and `@nobel/curves`
* Remove `bip32` and `bip39` in favor of `@scure/bip32` and `@scure/bip39`
* Remove `assert` dependency. If you were catching `AssertionError` you need to change to `Error`
* Configuring a proxy:
* Instead of passing various parameters on the `ConnectionsOptions` you know specify the `agent` parameter. This object can use be created by libraries such as `https-proxy-agent` or any that implements the `http.Agent`.
* This was changed to both support the latest `https-proxy-agent` and to remove the need to include the package in bundlers. Tests will still be done using `https-proxy-agent` and only tested in a node environment which was the only way it was previously supported anyway
* Remove `BroadcastClient` which was deprecated
* Uses `@xrplf/secret-numbers` instead of `xrpl-secret-numbers`
* Improve key algorithm detection. It will now throw Errors with helpful messages
* Move `authorizeChannel` from `wallet/signer` to `wallet/authorizeChannel` to solve a circular dependency issue.
* When using a bundler you must remove the mapping of `ws` to `WSWrapper`. ex. `ws: 'xrpl/dist/npm/client/WSWrapper'`. See [../UNIQUE_STEPS](Unique Steps) for the new, much smaller, configs.
### Bundling Changes
Bundler configurations are much more simplified. See [../UNIQUE_STEPS](Unique Steps) for the new, much smaller, configs.
* removed the following polyfills:
* `assert`
* `crypto-browserify`
* `https-browserify`
* `os-browserify`
* `stream-browserify`
* `stream-http`
* `url`
* `util` - previously added automatically by `webpack`
* `events` - previously added automatically by `webpack` but manual for `vite`
* Removed mappings for:
* `ws` to `WsWrapper`
* Excluding `https-proxy-agent`
### Changed
* Remove `lodash` as a dependency
* Remove many polyfills that were only used for testing in the browser
* Remove `util` from bundle by switching `inspect` to `JSON.stringify`
* Add type for metadata for specific transactions(`Payment`, `NFTokenMint`, `NFTokenCreateOffer`, `NFTokenAcceptOffer`, `NFTokenCancelOffer`)
### Fixed
* Fixed Wallet.generate() ignoring the `algorithm` parameter (Only a problem once binary-codec fix for `derive_keypair` is added)
* Fixed Wallet.fromSeed() ignoring the `algorithm` parameter
* Added pseudo-transaction support to hash functions and response types
## 2.14.1 (2024-02-01)

View File

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

View File

@@ -1,5 +1,11 @@
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')
async function createTxWithPaths(): Promise<void> {
@@ -8,22 +14,17 @@ async function createTxWithPaths(): Promise<void> {
const { wallet } = await client.fundWallet(null, {
usageContext: 'code snippets',
})
const destination_account = 'rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj'
const destination_account = 'rJPeZVPty1bXXbDR9oKscg2irqABr7sP3t'
const destination_amount = {
value: '0.001',
currency: 'USD',
issuer: 'rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc',
currency: 'TST',
issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
}
const resp = await client.request({
// TOOD: Replace with path_find - https://github.com/XRPLF/xrpl.js/issues/2385
command: 'ripple_path_find',
command: 'path_find',
subcommand: 'create',
source_account: wallet.classicAddress,
source_currencies: [
{
currency: 'XRP',
},
],
destination_account,
destination_amount,
})

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,21 +2,37 @@ import BigNumber from 'bignumber.js'
import { decode } from 'ripple-binary-codec'
import type {
AccountTxResponse,
TransactionEntryResponse,
TransactionStream,
TransactionV1Stream,
TxResponse,
} from '..'
import type { Amount } from '../models/common'
import type { RequestResponseMap } from '../models/methods'
import type {
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 { PaymentFlags, Transaction } from '../models/transactions'
import { PaymentFlags, Transaction, isMPTAmount } from '../models/transactions'
import type { TransactionMetadata } from '../models/transactions/metadata'
import { isFlagEnabled } from '../models/utils'
const WARN_PARTIAL_PAYMENT_CODE = 2001
function amountsEqual(amt1: Amount, amt2: Amount): boolean {
/* 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') {
return amt1 === amt2
}
@@ -25,15 +41,32 @@ function amountsEqual(amt1: Amount, amt2: Amount): boolean {
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 bValue = new BigNumber(amt2.value)
return (
amt1.currency === amt2.currency &&
amt1.issuer === amt2.issuer &&
(amt1 as IssuedCurrency).currency === (amt2 as IssuedCurrency).currency &&
(amt1 as IssuedCurrency).issuer === (amt2 as IssuedCurrency).issuer &&
aValue.isEqualTo(bValue)
)
}
/* eslint-enable complexity */
/* eslint-enable @typescript-eslint/consistent-type-assertions */
function isPartialPayment(
tx?: Transaction,
@@ -63,7 +96,10 @@ function isPartialPayment(
}
const delivered = meta.delivered_amount
const amount = tx.Amount
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- DeliverMax is a valid field on Payment response
// @ts-expect-error -- DeliverMax is a valid field on Payment response
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- DeliverMax is a valid field on Payment response
const amount = tx.DeliverMax
if (delivered === undefined) {
return false
@@ -73,23 +109,36 @@ function isPartialPayment(
}
function txHasPartialPayment(response: TxResponse): boolean {
return isPartialPayment(response.result, response.result.meta)
return isPartialPayment(response.result.tx_json, response.result.meta)
}
function txEntryHasPartialPayment(response: TransactionEntryResponse): boolean {
return isPartialPayment(response.result.tx_json, response.result.metadata)
}
function accountTxHasPartialPayment(response: AccountTxResponse): boolean {
function accountTxHasPartialPayment<
Version extends APIVersion = typeof DEFAULT_API_VERSION,
>(response: AccountTxVersionResponseMap<Version>): boolean {
const { transactions } = response.result
const foo = transactions.some((tx) => isPartialPayment(tx.tx, tx.meta))
const foo = transactions.some((tx) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- required to check API version model
if (tx.tx_json != null) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- use API v2 model
const transaction = tx as AccountTxTransaction
return isPartialPayment(transaction.tx_json, transaction.meta)
}
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- use API v1 model
const transaction = tx as AccountTxTransaction<1>
return isPartialPayment(transaction.tx, transaction.meta)
})
return foo
}
function hasPartialPayment<R extends BaseRequest, T = RequestResponseMap<R>>(
command: string,
response: T,
): boolean {
function hasPartialPayment<
R extends BaseRequest,
V extends APIVersion = typeof DEFAULT_API_VERSION,
T = RequestResponseMap<R, V>,
>(command: string, response: T): boolean {
/* eslint-disable @typescript-eslint/consistent-type-assertions -- Request type is known at runtime from command */
switch (command) {
case 'tx':
@@ -97,7 +146,9 @@ function hasPartialPayment<R extends BaseRequest, T = RequestResponseMap<R>>(
case 'transaction_entry':
return txEntryHasPartialPayment(response as TransactionEntryResponse)
case 'account_tx':
return accountTxHasPartialPayment(response as AccountTxResponse)
return accountTxHasPartialPayment(
response as AccountTxVersionResponseMap<V>,
)
default:
return false
}
@@ -112,7 +163,7 @@ function hasPartialPayment<R extends BaseRequest, T = RequestResponseMap<R>>(
*/
export function handlePartialPayment<
R extends BaseRequest,
T = RequestResponseMap<R>,
T = RequestResponseMap<R, APIVersion>,
>(command: string, response: T): void {
if (hasPartialPayment(command, response)) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We are checking dynamically and safely.
@@ -138,10 +189,10 @@ export function handlePartialPayment<
* @param log - The method used for logging by the connection (to report the partial payment).
*/
export function handleStreamPartialPayment(
stream: TransactionStream,
stream: TransactionStream | TransactionV1Stream,
log: (id: string, message: string) => void,
): void {
if (isPartialPayment(stream.transaction, stream.meta)) {
if (isPartialPayment(stream.tx_json ?? stream.transaction, stream.meta)) {
const warnings = stream.warnings ?? []
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 interface XRP {
@@ -16,6 +20,11 @@ export interface IssuedCurrencyAmount extends IssuedCurrency {
value: string
}
export interface MPTAmount {
mpt_issuance_id: string
value: string
}
export type Amount = IssuedCurrencyAmount | string
export interface Balance {
@@ -104,6 +113,10 @@ export interface ResponseOnlyTxInfo {
* The sequence number of the ledger that included this transaction.
*/
ledger_index?: number
/**
* The hash of the ledger included this transaction.
*/
ledger_hash?: string
/**
* @deprecated Alias for ledger_index.
*/
@@ -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 {
LockingChainDoor: string
LockingChainIssue: Currency
IssuingChainDoor: string
IssuingChainIssue: Currency
}
/**
* A PriceData object represents the price information for a token pair.
*
*/
export interface PriceData {
PriceData: {
/**
* The primary asset in a trading pair. Any valid identifier, such as a stock symbol, bond CUSIP, or currency code is allowed.
* For example, in the BTC/USD pair, BTC is the base asset; in 912810RR9/BTC, 912810RR9 is the base asset.
*/
BaseAsset: string
/**
* The quote asset in a trading pair. The quote asset denotes the price of one unit of the base asset. For example, in the
* BTC/USD pair,BTC is the base asset; in 912810RR9/BTC, 912810RR9 is the base asset.
*/
QuoteAsset: string
/**
* The asset price after applying the Scale precision level. It's not included if the last update transaction didn't include
* the BaseAsset/QuoteAsset pair.
*/
AssetPrice?: number | string
/**
* The scaling factor to apply to an asset price. For example, if Scale is 6 and original price is 0.155, then the scaled
* price is 155000. Valid scale ranges are 0-10. It's not included if the last update transaction didn't include the
* BaseAsset/QuoteAsset pair.
*/
Scale?: number
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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'
/**
@@ -12,8 +14,6 @@ export default interface DepositPreauth
LedgerEntryType: 'DepositPreauth'
/** The account that granted the preauthorization. */
Account: string
/** The account that received the preauthorization. */
Authorize: string
/**
* A bit-map of boolean flags. No flags are defined for DepositPreauth
* objects, so this value is always 0.
@@ -24,4 +24,8 @@ export default interface DepositPreauth
* object, in case the directory consists of multiple pages.
*/
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
@@ -8,7 +8,7 @@ import { BaseLedgerEntry, MissingPreviousTxnID } from './BaseLedgerEntry'
*/
export default interface DirectoryNode
extends BaseLedgerEntry,
MissingPreviousTxnID {
HasOptionalPreviousTxnID {
LedgerEntryType: 'DirectoryNode'
/**
* A bit-map of boolean flags enabled for this directory. Currently, the

View File

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

View File

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

View File

@@ -3,6 +3,7 @@ import Amendments from './Amendments'
import AMM from './AMM'
import Bridge from './Bridge'
import Check from './Check'
import Credential from './Credential'
import DepositPreauth from './DepositPreauth'
import DirectoryNode from './DirectoryNode'
import Escrow from './Escrow'
@@ -10,6 +11,7 @@ import FeeSettings from './FeeSettings'
import LedgerHashes from './LedgerHashes'
import NegativeUNL from './NegativeUNL'
import Offer from './Offer'
import Oracle from './Oracle'
import PayChannel from './PayChannel'
import RippleState from './RippleState'
import SignerList from './SignerList'
@@ -23,6 +25,7 @@ type LedgerEntry =
| AMM
| Bridge
| Check
| Credential
| DepositPreauth
| DirectoryNode
| Escrow
@@ -30,6 +33,7 @@ type LedgerEntry =
| LedgerHashes
| NegativeUNL
| Offer
| Oracle
| PayChannel
| RippleState
| SignerList
@@ -43,15 +47,19 @@ type LedgerEntryFilter =
| 'amm'
| 'bridge'
| 'check'
| 'credential'
| 'deposit_preauth'
| 'did'
| 'directory'
| 'escrow'
| 'fee'
| 'hashes'
| 'mpt_issuance'
| 'mptoken'
| 'nft_offer'
| 'nft_page'
| 'offer'
| 'oracle'
| 'payment_channel'
| 'signer_list'
| 'state'

View File

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

View File

@@ -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
@@ -14,7 +14,7 @@ export const NEGATIVE_UNL_ID =
*/
export default interface NegativeUNL
extends BaseLedgerEntry,
MissingPreviousTxnID {
HasOptionalPreviousTxnID {
LedgerEntryType: 'NegativeUNL'
/**
* A list of trusted validators that are currently disabled.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,
isNumber,
validateBaseTransaction,
validateCredentialsList,
validateOptionalField,
validateRequiredField,
} from './common'
@@ -28,6 +29,12 @@ export interface AccountDelete extends BaseTransaction {
* information for the recipient of the deleted account's leftover XRP.
*/
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)
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 { IssuedCurrencyAmount } from '../common'
import { IssuedCurrencyAmount, MPTAmount } from '../common'
import {
BaseTransaction,
validateBaseTransaction,
isIssuedCurrency,
isMPTAmount,
isAccount,
validateOptionalField,
} from './common'
/**
@@ -15,15 +18,20 @@ export interface Clawback extends BaseTransaction {
TransactionType: 'Clawback'
/**
* 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
/**
* The amount of currency to deliver, and it must be non-XRP. The nested field
* names MUST be lower-case. The `issuer` field MUST be the holder's address,
* The amount of currency or MPT to clawback, and it must be non-XRP. The nested field
* names MUST be lower-case. If the amount is IOU, the `issuer` field MUST be the holder's address,
* 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 {
validateBaseTransaction(tx)
validateOptionalField(tx, 'Holder', isAccount)
if (tx.Amount == null) {
throw new ValidationError('Clawback: missing field Amount')
}
if (!isIssuedCurrency(tx.Amount)) {
if (!isIssuedCurrency(tx.Amount) && !isMPTAmount(tx.Amount)) {
throw new ValidationError('Clawback: invalid Amount')
}
if (isIssuedCurrency(tx.Amount) && tx.Account === tx.Amount.issuer) {
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 { TRANSACTION_TYPES } from 'ripple-binary-codec'
import { ValidationError } from '../../errors'
import {
Amount,
AuthorizeCredential,
Currency,
IssuedCurrencyAmount,
Memo,
Signer,
XChainBridge,
MPTAmount,
} from '../common'
import { onlyHasFields } from '../utils'
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 {
if (obj.Memo == null) {
@@ -59,6 +66,8 @@ const XRP_CURRENCY_SIZE = 1
const ISSUE_SIZE = 2
const ISSUED_CURRENCY_SIZE = 3
const XCHAIN_BRIDGE_SIZE = 4
const MPTOKEN_SIZE = 2
const AUTHORIZE_CREDENTIAL_SIZE = 1
function isRecord(value: unknown): value is Record<string, unknown> {
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
*/
@@ -144,7 +184,11 @@ export function isAccount(account: unknown): account is Account {
* @returns Whether the Amount is properly formed.
*/
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)
}
/**
* 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 { AuthorizeCredential } from '../common'
import { BaseTransaction, validateBaseTransaction } from './common'
import {
BaseTransaction,
validateBaseTransaction,
validateCredentialsList,
} from './common'
/**
* A DepositPreauth transaction gives another account pre-approval to deliver
@@ -18,6 +23,16 @@ export interface DepositPreauth extends BaseTransaction {
* revoked.
*/
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 {
validateBaseTransaction(tx)
if (tx.Authorize !== undefined && tx.Unauthorize !== undefined) {
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',
)
}
validateSingleAuthorizationFieldProvided(tx)
if (tx.Authorize !== undefined) {
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",
)
}
}
if (tx.Unauthorize !== undefined) {
} else if (tx.Unauthorize !== undefined) {
if (typeof tx.Unauthorize !== '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",
)
}
} 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,
isAccount,
validateBaseTransaction,
validateCredentialsList,
validateRequiredField,
} from './common'
@@ -32,6 +33,10 @@ export interface EscrowFinish extends BaseTransaction {
* the held payment's Condition.
*/
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)
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) {
throw new ValidationError('EscrowFinish: missing field OfferSequence')
}

View File

@@ -1,4 +1,4 @@
export { BaseTransaction } from './common'
export { BaseTransaction, isMPTAmount } from './common'
export {
validate,
PseudoTransaction,
@@ -32,6 +32,9 @@ export { CheckCancel } from './checkCancel'
export { CheckCash } from './checkCash'
export { CheckCreate } from './checkCreate'
export { Clawback } from './clawback'
export { CredentialAccept } from './CredentialAccept'
export { CredentialCreate } from './CredentialCreate'
export { CredentialDelete } from './CredentialDelete'
export { DIDDelete } from './DIDDelete'
export { DIDSet } from './DIDSet'
export { DepositPreauth } from './depositPreauth'
@@ -39,6 +42,22 @@ export { EscrowCancel } from './escrowCancel'
export { EscrowCreate } from './escrowCreate'
export { EscrowFinish } from './escrowFinish'
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 { NFTokenBurn } from './NFTokenBurn'
export { NFTokenCancelOffer } from './NFTokenCancelOffer'
@@ -58,6 +77,8 @@ export {
OfferCreateFlagsInterface,
OfferCreate,
} from './offerCreate'
export { OracleDelete } from './oracleDelete'
export { OracleSet } from './oracleSet'
export { PaymentFlags, PaymentFlagsInterface, Payment } from './payment'
export {
PaymentChannelClaimFlags,

View File

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