mirror of
https://github.com/Xahau/xahau.js.git
synced 2026-06-20 09:06:44 +00:00
Compare commits
38 Commits
xahau@4.0.
...
xahau@4.1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9a22ffa23 | ||
|
|
e351c57e88 | ||
|
|
8f1c5db1f3 | ||
|
|
18d343fcb5 | ||
|
|
0c6578156f | ||
|
|
4cd8736eb4 | ||
|
|
5e789b1d10 | ||
|
|
8dbe640aa9 | ||
|
|
4fc68a4bbf | ||
|
|
deaf6af88b | ||
|
|
64608cb9a6 | ||
|
|
cc5cf1f2ea | ||
|
|
b417d67b28 | ||
|
|
bf788fe7b9 | ||
|
|
3c7609429f | ||
|
|
b85f34d16f | ||
|
|
c70e4c1eee | ||
|
|
4918e914c5 | ||
|
|
7552ae8635 | ||
|
|
fd100f6e92 | ||
|
|
587a75403a | ||
|
|
9444693967 | ||
|
|
1de9e4e35b | ||
|
|
fd43b82827 | ||
|
|
b310c6c25a | ||
|
|
a8939c883b | ||
|
|
05e8c2dbda | ||
|
|
e838caaffc | ||
|
|
b9fb8a1924 | ||
|
|
de97ef13e9 | ||
|
|
c1aed4ef48 | ||
|
|
35c294218d | ||
|
|
58150f156e | ||
|
|
d7b3a02ad2 | ||
|
|
ac33a1584d | ||
|
|
8bbc84057c | ||
|
|
0ca36e1314 | ||
|
|
e454c61994 |
8
.ci-config/validators.txt
Normal file
8
.ci-config/validators.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
[validator_list_sites]
|
||||
http://vl/vl.json
|
||||
|
||||
[validator_list_keys]
|
||||
ED87E0EA91AAFFA130B78B75D2CC3E53202AA1BD8AB3D5E7BAC530C8440E328501
|
||||
|
||||
[import_vl_keys]
|
||||
ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1
|
||||
@@ -101,69 +101,105 @@ r.ripple.com 51235
|
||||
# If you need the version of rippled to be more up to date, you may need to make a comment on this repo: https://github.com/WietseWind/docker-rippled
|
||||
|
||||
[features]
|
||||
# Amendments
|
||||
NegativeUNL
|
||||
fixGuardDepth32
|
||||
NamedHooks
|
||||
IOURewardClaim
|
||||
fixIOULockedBalanceInvariant
|
||||
fixImportIssuer
|
||||
HookAPISerializedType240
|
||||
# PermissionedDomains Supported::no
|
||||
# DynamicNFT Supported::no
|
||||
# Credentials Supported::no
|
||||
AMMClawback
|
||||
# MPTokensV1 Supported::no
|
||||
# InvariantsV1_1 Supported::no
|
||||
fixNFTokenPageLinks
|
||||
fixEnforceNFTokenTrustline
|
||||
fixReducedOffersV2
|
||||
# NFTokenMintOffer Supported::no
|
||||
fixPreviousTxnID
|
||||
PriceOracle
|
||||
fixInnerObjTemplate
|
||||
fixNFTokenReserve
|
||||
fixFillOrKill
|
||||
# DID Supported::no
|
||||
fixDisallowIncomingV1
|
||||
# XChainBridge Supported::no
|
||||
AMM
|
||||
fixReducedOffersV1
|
||||
HooksUpdate2
|
||||
HookOnV2
|
||||
fixHookAPI20251128
|
||||
fixCronStacking
|
||||
ExtendedHookState
|
||||
fixInvalidTxFlags
|
||||
Cron
|
||||
IOUIssuerWeakTSH
|
||||
DeepFreeze
|
||||
fixProvisionalDoubleThreading
|
||||
Clawback
|
||||
fixRewardClaimFlags
|
||||
HookCanEmit
|
||||
fix20250131
|
||||
fixXahauV3
|
||||
fixReduceImport
|
||||
Touch
|
||||
Remarks
|
||||
fixFloatDivide
|
||||
fix240911
|
||||
fixPageCap
|
||||
fix240819
|
||||
fixNSDelete
|
||||
ZeroB2M
|
||||
Remit
|
||||
fixXahauV2
|
||||
fixXahauV1
|
||||
HooksUpdate1
|
||||
XahauGenesis
|
||||
Import
|
||||
URIToken
|
||||
PaychanAndEscrowForTokens
|
||||
BalanceRewards
|
||||
Hooks
|
||||
fixNFTokenRemint
|
||||
fixNonFungibleTokensV1_2
|
||||
fixUniversalNumber
|
||||
XRPFees
|
||||
DisallowIncoming
|
||||
ImmediateOfferKilled
|
||||
fixRemoveNFTokenAutoTrustLine
|
||||
NonFungibleTokensV1
|
||||
fixTrustLinesToSelf
|
||||
NonFungibleTokensV1_1
|
||||
ExpandedSignerList
|
||||
CheckCashMakesTrustLine
|
||||
fixRmSmallIncreasedQOffers
|
||||
fixSTAmountCanonicalize
|
||||
FlowSortStrands
|
||||
TicketBatch
|
||||
fixQualityUpperBound
|
||||
FlowCross
|
||||
HardenedValidations
|
||||
DepositPreauth
|
||||
MultiSignReserve
|
||||
fix1623
|
||||
fix1513
|
||||
RequireFullyCanonicalSig
|
||||
fix1543
|
||||
fix1781
|
||||
fixCheckThreading
|
||||
fix1515
|
||||
CryptoConditionsSuite
|
||||
fixPayChanRecipientOwnerDir
|
||||
fix1578
|
||||
fix1571
|
||||
NegativeUNL
|
||||
fixAmendmentMajorityCalc
|
||||
fixTakerDryOfferRemoval
|
||||
fixMasterKeyAsRegularKey
|
||||
Flow
|
||||
HardenedValidations
|
||||
fix1781
|
||||
RequireFullyCanonicalSig
|
||||
fixQualityUpperBound
|
||||
DeletableAccounts
|
||||
DepositAuth
|
||||
fixPayChanRecipientOwnerDir
|
||||
fixCheckThreading
|
||||
fixMasterKeyAsRegularKey
|
||||
fixTakerDryOfferRemoval
|
||||
MultiSignReserve
|
||||
fix1578
|
||||
fix1515
|
||||
DepositPreauth
|
||||
fix1623
|
||||
fix1543
|
||||
fix1571
|
||||
Checks
|
||||
NonFungibleTokensV1_1
|
||||
DisallowIncoming
|
||||
fixNonFungibleTokensV1_2
|
||||
fixUniversalNumber
|
||||
ImmediateOfferKilled
|
||||
XRPFees
|
||||
ExpandedSignerList
|
||||
fixNFTokenRemint
|
||||
# Additional Amendments
|
||||
BalanceRewards
|
||||
Hooks
|
||||
HooksUpdate1
|
||||
Import
|
||||
Remit
|
||||
URIToken
|
||||
XahauGenesis
|
||||
ZeroB2M
|
||||
fix240819
|
||||
fix240911
|
||||
fixFloatDivide
|
||||
fixNFTokenDirV1
|
||||
fixNFTokenNegOffer
|
||||
fixNSDelete
|
||||
fixPageCap
|
||||
fixReduceImport
|
||||
fixXahauV1
|
||||
fixXahauV2
|
||||
fixXahauV3
|
||||
PaychanAndEscrowForTokens
|
||||
DeepFreeze
|
||||
Clawback
|
||||
DepositAuth
|
||||
fix1513
|
||||
FlowCross
|
||||
Flow
|
||||
# OwnerPaysFee Supported::no
|
||||
|
||||
[network_id]
|
||||
21337
|
||||
|
||||
67
.github/workflows/nodejs.yml
vendored
67
.github/workflows/nodejs.yml
vendored
@@ -4,7 +4,7 @@
|
||||
name: Node.js CI
|
||||
|
||||
env:
|
||||
XAHAUD_DOCKER_IMAGE: xahauci/xahaud:2025.2.6
|
||||
XAHAUD_VERSION: 2026.6.16-dev+3330
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
node-version: [20.x, 22.x, 24.x, 26.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x, 20.x]
|
||||
node-version: [20.x, 22.x, 24.x, 26.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -95,20 +95,55 @@ jobs:
|
||||
- run: npm run build
|
||||
- run: npm test
|
||||
|
||||
download-binary:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: cache binary
|
||||
id: cache-binary
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: xahaud
|
||||
key: ${{ runner.os }}-xahaud-${{ env.XAHAUD_VERSION }}
|
||||
|
||||
- name: Download binary
|
||||
if: steps.cache-binary.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
wget https://build.xahau.tech/${{ env.XAHAUD_VERSION }} -q -O xahaud
|
||||
chmod +x xahaud
|
||||
|
||||
integration:
|
||||
runs-on: ubuntu-latest
|
||||
needs: download-binary
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x, 20.x]
|
||||
node-version: [20.x, 22.x, 24.x, 26.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Restore binary
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: xahaud
|
||||
key: ${{ runner.os }}-xahaud-${{ env.XAHAUD_VERSION }}
|
||||
|
||||
- name: Run docker in background
|
||||
run: |
|
||||
docker run --detach --rm --name xahaud-service -p 6006:6006 --volume "${{ github.workspace }}/.ci-config/":"/opt/xahau/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.XAHAUD_DOCKER_IMAGE }} /opt/xahau/bin/xahaud -a --conf /opt/xahau/etc/xahaud.cfg
|
||||
docker run --detach --rm \
|
||||
--name xahaud-service \
|
||||
-p 6006:6006 \
|
||||
--volume "${{ github.workspace }}/.ci-config/":"/opt/xahau/etc/" \
|
||||
--volume "${{ github.workspace }}/xahaud":"/opt/xahau/bin/xahaud" \
|
||||
--health-cmd="wget localhost:6006 || exit 1" \
|
||||
--health-interval=5s \
|
||||
--health-retries=10 \
|
||||
--health-timeout=2s \
|
||||
--env GITHUB_ACTIONS=true \
|
||||
--env CI=true \
|
||||
ubuntu:latest /opt/xahau/bin/xahaud -a --conf /opt/xahau/etc/xahaud.cfg
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
@@ -149,11 +184,12 @@ jobs:
|
||||
|
||||
browser:
|
||||
runs-on: ubuntu-latest
|
||||
needs: download-binary
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
node-version: [20.x, 22.x, 24.x, 26.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -163,9 +199,26 @@ jobs:
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Restore binary
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: xahaud
|
||||
key: ${{ runner.os }}-xahaud-${{ env.XAHAUD_VERSION }}
|
||||
|
||||
- name: Run docker in background
|
||||
run: |
|
||||
docker run --detach --rm --name xahaud-service -p 6006:6006 --volume "${{ github.workspace }}/.ci-config/":"/opt/xahau/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.XAHAUD_DOCKER_IMAGE }} /opt/xahau/bin/xahaud -a --conf /opt/xahau/etc/xahaud.cfg
|
||||
docker run --detach --rm \
|
||||
--name xahaud-service \
|
||||
-p 6006:6006 \
|
||||
--volume "${{ github.workspace }}/.ci-config/":"/opt/xahau/etc/" \
|
||||
--volume "${{ github.workspace }}/xahaud":"/opt/xahau/bin/xahaud" \
|
||||
--health-cmd="wget localhost:6006 || exit 1" \
|
||||
--health-interval=5s \
|
||||
--health-retries=10 \
|
||||
--health-timeout=2s \
|
||||
--env GITHUB_ACTIONS=true \
|
||||
--env CI=true \
|
||||
ubuntu:latest /opt/xahau/bin/xahaud -a --conf /opt/xahau/etc/xahaud.cfg
|
||||
|
||||
- name: Setup npm version 9
|
||||
run: |
|
||||
|
||||
109
.github/workflows/npm-publish.yml
vendored
Normal file
109
.github/workflows/npm-publish.yml
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
name: Publish npm packages
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
concurrency:
|
||||
group: npm-publish-${{ github.event.release.tag_name }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish ${{ github.event.release.tag_name }}
|
||||
runs-on: ubuntu-latest
|
||||
environment: npm
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- id: release
|
||||
name: Resolve package from tag
|
||||
shell: bash
|
||||
run: |
|
||||
case "$RELEASE_TAG" in
|
||||
xahau@*) package_path="packages/xahau" ;;
|
||||
xahau-address-codec@*) package_path="packages/xahau-address-codec" ;;
|
||||
xahau-binary-codec@*) package_path="packages/xahau-binary-codec" ;;
|
||||
xahau-keypairs@*) package_path="packages/xahau-keypairs" ;;
|
||||
*)
|
||||
echo "Unsupported release tag: $RELEASE_TAG" >&2
|
||||
echo "Expected xahau@<version>, xahau-address-codec@<version>, xahau-binary-codec@<version>, or xahau-keypairs@<version>." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "package-path=$package_path" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name }}
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "24"
|
||||
registry-url: https://registry.npmjs.org
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build package
|
||||
run: npm run build
|
||||
|
||||
- id: package
|
||||
name: Read package metadata
|
||||
shell: bash
|
||||
run: |
|
||||
package_json="${{ steps.release.outputs.package-path }}/package.json"
|
||||
name="$(jq -r .name "$package_json")"
|
||||
version="$(jq -r .version "$package_json")"
|
||||
tag="$name@$version"
|
||||
if [[ "$version" == *"-"* ]]; then
|
||||
release_tag="${version#*-}"
|
||||
release_tag="${release_tag%%.*}"
|
||||
else
|
||||
release_tag="latest"
|
||||
fi
|
||||
|
||||
{
|
||||
echo "name=$name"
|
||||
echo "version=$version"
|
||||
echo "tag=$tag"
|
||||
echo "release_tag=$release_tag"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check release tag matches package version
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ "$RELEASE_TAG" != "$PACKAGE_TAG" ]]; then
|
||||
echo "Release tag $RELEASE_TAG does not match package tag $PACKAGE_TAG." >&2
|
||||
exit 1
|
||||
fi
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
PACKAGE_TAG: ${{ steps.package.outputs.tag }}
|
||||
|
||||
- name: Check package version is unpublished
|
||||
shell: bash
|
||||
run: |
|
||||
package_spec="${{ steps.package.outputs.tag }}"
|
||||
stderr_file="$(mktemp)"
|
||||
|
||||
if npm view "$package_spec" version --registry https://registry.npmjs.org 2>"$stderr_file"; then
|
||||
echo "$package_spec is already published." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -Eq "E404|404 Not Found|is not in this registry" "$stderr_file"; then
|
||||
echo "$package_spec is not published yet."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cat "$stderr_file" >&2
|
||||
exit 1
|
||||
|
||||
- name: Publish to npm
|
||||
run: npm publish --workspace "${{ steps.release.outputs.package-path }}" --registry https://registry.npmjs.org --tag "${{ steps.package.outputs.release_tag }}"
|
||||
@@ -226,49 +226,51 @@ This should almost always be done using the [`xrpl-codec-gen`](https://github.co
|
||||
## Release
|
||||
|
||||
1. Checkout `main` (or your beta branch) and `git pull`.
|
||||
1. Create a new branch (`git checkout -b <BRANCH_NAME>`) to capture updates that take place during this process.
|
||||
1. Update `HISTORY.md` to reflect release changes.
|
||||
2. Create a new branch (`git checkout -b <BRANCH_NAME>`) to capture updates that take place during this process.
|
||||
3. Update `HISTORY.md` to reflect release changes.
|
||||
|
||||
- [ ] Update the version number and release date, and ensure it lists the changes since the previous release.
|
||||
|
||||
1. Run `npm run docgen` if the docs were modified in this release to update them (skip this step for a beta).
|
||||
1. Run `npm run build` to triple check the build still works
|
||||
1. Run `npx lerna version --no-git-tag-version` - This bumps the package versions.
|
||||
4. Run `npm run docgen` if the docs were modified in this release to update them (skip this step for a beta).
|
||||
5. Run `npm run clean` to delete previously generated artifacts.
|
||||
6. Run `npm run build` to triple check the build still works
|
||||
7. Run `npx lerna version --no-git-tag-version` - This bumps the package versions.
|
||||
|
||||
- For each changed package, pick what the new version should be. Lerna will bump the versions, commit version bumps to `main`, and create a new git tag for each published package.
|
||||
- If you do NOT want to update the package number, choose "Custom Version" and set the version to be the same as the existing version. Lerna will not publish any changes in this case.
|
||||
- If publishing a beta, make sure that the versions are all of the form `a.b.c-beta.d`, where `a`, `b`, and `c` are identical to the last normal release except for one, which has been incremented by 1.
|
||||
|
||||
1. Run `npm i` to update the package-lock with the updated versions.
|
||||
1. Create a new PR from this branch into `main` and merge it (you can directly merge into the beta branch for a beta).
|
||||
1. Checkout `main` and `git pull` (you can skip this step for a beta since you already have the latest version of the beta branch).
|
||||
1. Actually publish the packages with one of the following:
|
||||
8. Run `npm i` to update the package-lock with the updated versions.
|
||||
9. Create a new PR from this branch into `main` and merge it (you can directly merge into the beta branch for a beta).
|
||||
10. Checkout `main` and `git pull` (you can skip this step for a beta since you already have the latest version of the beta branch).
|
||||
11. Actually publish the packages with one of the following:
|
||||
|
||||
- Stable release: Run `npx lerna publish from-package --yes`
|
||||
- Beta release: Run `npx lerna publish from-package --dist-tag beta --yes`
|
||||
Notice this allows developers to install the package with `npm add xahau@beta`
|
||||
- Stable release: Run `npx lerna publish from-package --yes`
|
||||
- Beta release: Run `npx lerna publish from-package --dist-tag beta --yes`
|
||||
Notice this allows developers to install the package with `npm add xahau@beta`
|
||||
|
||||
1. If requested, enter your [npmjs.com](https://npmjs.com) OTP (one-time password) to complete publication.
|
||||
12. If requested, enter your [npmjs.com](https://npmjs.com) OTP (one-time password) to complete publication.
|
||||
|
||||
NOW YOU HAVE PUBLISHED! But you're not done; we have to notify people!
|
||||
NOW YOU HAVE PUBLISHED! But you're not done; we have to notify people!
|
||||
|
||||
1. Run `git tag <tagname> -m <tagname>`, where `<tagname>` is the new package and version (e.g. `xahau@2.1.1`), for each version released.
|
||||
1. Run `git push --follow-tags`, to push the tags to Github.
|
||||
1. On GitHub, click the "Releases" link on the right-hand side of the page.
|
||||
13. Run `git tag <tagname> -m <tagname>`, where `<tagname>` is the new package and version (e.g. `xahau@2.1.1`), for each version released.
|
||||
14. Run `git push --follow-tags`, to push the tags to Github.
|
||||
15. On GitHub, click the "Releases" link on the right-hand side of the page.
|
||||
|
||||
1. Repeat for each release:
|
||||
16. Repeat for each release:
|
||||
|
||||
1. Click "Draft a new release"
|
||||
1. Click "Choose a tag", and choose a tag that you just created.
|
||||
1. Edit the name of the release to match the tag (IE \<package\>@\<version\>) and edit the description as you see fit.
|
||||
1. Click "Draft a new release"
|
||||
2. Click "Choose a tag", and choose a tag that you just created.
|
||||
3. Edit the name of the release to match the tag (IE \<package\>@\<version\>) and edit the description as you see fit.
|
||||
|
||||
1. Send an email to [xahau-announce](https://groups.google.com/g/xahau-announce).
|
||||
1. Lastly, send a similar message to the Xahau Discord in the [`javascript` channel](https://discord.com/channels/1085202760548499486/1085203623111295068). The message should include:
|
||||
17. Send an email to [xahau-announce](https://groups.google.com/g/xahau-announce).
|
||||
18. Lastly, send a similar message to the Xahau Discord in the [`javascript` channel](https://discord.com/channels/1085202760548499486/1085203623111295068). The message should include:
|
||||
1. The version changes for xahau libraries
|
||||
1. A link to the more detailed changes
|
||||
1. Highlights of important changes
|
||||
2. A link to the more detailed changes
|
||||
3. Highlights of important changes
|
||||
|
||||
|
||||
<!--
|
||||
## Mailing Lists
|
||||
|
||||
We have a low-traffic mailing list for announcements of new `xahau.js` releases. (About 1 email every couple of weeks)
|
||||
@@ -278,3 +280,4 @@ We have a low-traffic mailing list for announcements of new `xahau.js` releases.
|
||||
If you're using the Xahau Ledger in production, you should run a [xahaud server](https://github.com/xahau/xahaud) and subscribe to the xahau-server mailing list as well.
|
||||
|
||||
- [Subscribe to xahau-server](https://groups.google.com/g/xahau-server)
|
||||
-->
|
||||
|
||||
@@ -86,6 +86,7 @@ As you develop with xahau.js, there's two sites you'll use extensively:
|
||||
- What kinds of transactions there are ([Transaction Types](https://docs.xahau.network/technical/protocol-reference/transactions/transaction-types))
|
||||
- Requests you can send ([Public API Methods](https://docs.xahau.network/features/http-websocket-apis))
|
||||
|
||||
<!--
|
||||
### Mailing Lists
|
||||
|
||||
If you want to hear when we release new versions of xahau.js, you can join our low-traffic mailing list (About 1 email per week):
|
||||
@@ -97,3 +98,4 @@ If you're using the Xahau Ledger in production, you should run a [xahaud server]
|
||||
- [Subscribe to xahau-server](https://groups.google.com/g/xahau-server)
|
||||
|
||||
You are also welcome to create an [issue](https://github.com/Xahau/xahau.js/issues) here and we'll do our best to respond within 3 days.
|
||||
-->
|
||||
|
||||
8
command.sh
Executable file
8
command.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
for file in $(git log --diff-filter=D --name-only --format="" | grep -E "oracle.*\.ts$"); do
|
||||
commit=$(git rev-list -n 1 HEAD -- "$file")
|
||||
if [ ! -z "$commit" ]; then
|
||||
git checkout "$commit~1" -- "$file"
|
||||
echo "restore: $file"
|
||||
fi
|
||||
done
|
||||
rsync -av packages/xrpl/ packages/xahau/ && rm -rf packages/xrpl/
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"version": "independent",
|
||||
"useWorkspaces": true,
|
||||
"npmClient": "npm"
|
||||
}
|
||||
|
||||
7772
package-lock.json
generated
7772
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -16,10 +16,10 @@
|
||||
"dependencies": {
|
||||
"@xrplf/isomorphic": "file:packages/isomorphic",
|
||||
"@xrplf/secret-numbers": "file:packages/secret-numbers",
|
||||
"xahau": "file:packages/xahau",
|
||||
"xahau-address-codec": "file:packages/xahau-address-codec",
|
||||
"xahau-binary-codec": "file:packages/xahau-binary-codec",
|
||||
"xahau-keypairs": "file:packages/xahau-keypairs",
|
||||
"xahau": "file:packages/xahau"
|
||||
"xahau-keypairs": "file:packages/xahau-keypairs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.2.21",
|
||||
@@ -45,7 +45,7 @@
|
||||
"expect": "^29.3.1",
|
||||
"jest": "^29.3.1",
|
||||
"jest-mock": "^29.3.1",
|
||||
"lerna": "^4.0.0",
|
||||
"lerna": "^9.0.7",
|
||||
"lodash": "^4.17.21",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.3.2",
|
||||
|
||||
@@ -4,6 +4,9 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
|
||||
|
||||
## Unreleased
|
||||
|
||||
### BREAKING CHANGES:
|
||||
* Renamed `build/xrplf-secret-numbers-latest.min.js` to `build/xrplf-secret-numbers-latest-min.js`.
|
||||
|
||||
## 1.0.0 (2024-02-01)
|
||||
|
||||
### BREAKING CHANGES:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepublish": "npm run clean && npm run lint && npm run test && npm run test:browser && npm run build",
|
||||
"clean": "rm -rf ./dist ./coverage ./test/testCompiledForWeb tsconfig.build.tsbuildinfo",
|
||||
"clean": "rm -rf ./build ./dist ./coverage ./test/testCompiledForWeb tsconfig.build.tsbuildinfo",
|
||||
"test": "jest --verbose",
|
||||
"test:browser": "npm run build && npm run build:browserTests && karma start ./karma.config.js",
|
||||
"build": "run-s build:lib build:web",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "xahau-address-codec",
|
||||
"version": "5.0.0",
|
||||
"description": "encodes/decodes base58 encoded XAH Ledger identifiers",
|
||||
"description": "encodes/decodes base58 encoded Xahau Network identifiers",
|
||||
"files": [
|
||||
"dist/*",
|
||||
"src/*"
|
||||
|
||||
@@ -162,9 +162,9 @@ export {
|
||||
encodeAccountID,
|
||||
// Decode a classic address to its raw bytes
|
||||
decodeAccountID,
|
||||
// Encode bytes to XAH Ledger node public key format
|
||||
// Encode bytes to Xahau Network node public key format
|
||||
encodeNodePublic,
|
||||
// Decode an XAH Ledger node public key into its raw bytes
|
||||
// Decode an Xahau Network node public key into its raw bytes
|
||||
decodeNodePublic,
|
||||
// Encode a public key, as for payment channels
|
||||
encodeAccountPublic,
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 2.1.0 (2024-06-03)
|
||||
|
||||
### Added
|
||||
* Support for the Price Oracles amendment (XLS-47).
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "xahau-binary-codec",
|
||||
"version": "2.1.1",
|
||||
"description": "XAH Ledger binary codec",
|
||||
"version": "2.2.0-alpha.0",
|
||||
"description": "Xahau Network binary codec",
|
||||
"files": [
|
||||
"dist/*",
|
||||
"src/*"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -74,7 +74,13 @@ class XrplDefinitionsBase {
|
||||
.filter(([_key, value]) => value >= 0)
|
||||
.map(([key, _value]) => key)
|
||||
|
||||
const ignoreList = ['EnableAmendment', 'SetFee', 'UNLModify', 'EmitFailure']
|
||||
const ignoreList = [
|
||||
'EnableAmendment',
|
||||
'SetFee',
|
||||
'UNLModify',
|
||||
'EmitFailure',
|
||||
'Cron',
|
||||
]
|
||||
this.transactionMap = Object.assign(
|
||||
{},
|
||||
...Object.entries(enums.TRANSACTION_TYPES)
|
||||
|
||||
@@ -4449,6 +4449,36 @@
|
||||
"Flags": 0,
|
||||
"Sequence": 62
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "12003C2FFFFFFFFF2033000004D2750B6469645F6578616D706C65701D0863757272656E6379701E0870726F7669646572811401476926B590BA3245F63C829116A0A3AF7F382DF018E020301700000000000001E2041003011A0000000000000000000000000000000000000000021A0000000000000000000000005553440000000000E1F1",
|
||||
"json": {
|
||||
"TransactionType": "OracleSet",
|
||||
"Account": "rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8",
|
||||
"OracleDocumentID": 1234,
|
||||
"LastUpdateTime": 4294967295,
|
||||
"PriceDataSeries": [
|
||||
{
|
||||
"PriceData": {
|
||||
"BaseAsset": "XAH",
|
||||
"QuoteAsset": "USD",
|
||||
"AssetPrice": "00000000000001E2",
|
||||
"Scale": 3
|
||||
}
|
||||
}
|
||||
],
|
||||
"Provider": "70726F7669646572",
|
||||
"URI": "6469645F6578616D706C65",
|
||||
"AssetClass": "63757272656E6379"
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "12003D2033000004D2811401476926B590BA3245F63C829116A0A3AF7F382D",
|
||||
"json": {
|
||||
"TransactionType": "OracleDelete",
|
||||
"Account": "rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8",
|
||||
"OracleDocumentID": 1234
|
||||
}
|
||||
}
|
||||
],
|
||||
"ledgerData": [{
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "xahau-keypairs",
|
||||
"version": "2.0.0",
|
||||
"description": "Cryptographic key pairs for the XAH Ledger",
|
||||
"description": "Cryptographic key pairs for the Xahau Network",
|
||||
"scripts": {
|
||||
"build": "tsc --build tsconfig.build.json",
|
||||
"test": "jest --verbose false --silent=false ./test/*.test.ts",
|
||||
|
||||
@@ -47,7 +47,7 @@ const ed25519: SigningScheme = {
|
||||
// ZIP 215 is a stricter Ed25519 signature verification scheme.
|
||||
// However, setting it to false adheres to the more commonly used
|
||||
// RFC8032 / NIST186-5 standards, making it compatible with systems
|
||||
// like the XAH Ledger.
|
||||
// like the Xahau Network.
|
||||
{ zip215: false },
|
||||
)
|
||||
},
|
||||
|
||||
@@ -4,6 +4,36 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
|
||||
|
||||
## Unreleased Changes
|
||||
|
||||
### Added
|
||||
* Support for HookOnV2 Amendment
|
||||
* Support for IOUClaimReward Amendment
|
||||
* Support for NamedHooks
|
||||
* Support for the `simulate` RPC ([XLS-69](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069-simulate))
|
||||
* Support for the Price Oracles amendment (XLS-47).
|
||||
|
||||
## 4.0.4 (2026-05-27)
|
||||
|
||||
### Added
|
||||
* Improve HookStateScale validation
|
||||
|
||||
### Fixed
|
||||
* Add lsfTshCollect flag in AccountRoot
|
||||
* Refactor amount assignment in partialPayment.ts
|
||||
* Fix setTransactionFlagsToNumber for Xahau transactions
|
||||
|
||||
## 4.0.3 (2025-11-18)
|
||||
|
||||
### Added
|
||||
* Fixed minified `build/xahau-latest-min.js` to have all the latest xahau package changes.
|
||||
|
||||
## 4.0.2 (2025-11-12)
|
||||
|
||||
### Added
|
||||
* Support for Cron Amendment
|
||||
* Support for ExtendedHookState Amendment
|
||||
|
||||
## 4.0.1 (2025-10-03)
|
||||
|
||||
### Added
|
||||
* parseTransactionFlags as a utility function in the xrpl package to streamline transactions flags-to-map conversion
|
||||
* Support for XLS-77d Deep-Freeze amendment
|
||||
@@ -38,6 +68,9 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
|
||||
### Added
|
||||
* Support for the Price Oracles amendment (XLS-47).
|
||||
|
||||
### 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
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "xahau",
|
||||
"version": "4.0.1",
|
||||
"version": "4.1.0-alpha.0",
|
||||
"license": "ISC",
|
||||
"description": "A TypeScript/JavaScript API for interacting with the XAH Ledger in Node.js and the browser",
|
||||
"description": "A TypeScript/JavaScript API for interacting with the Xahau Network in Node.js and the browser",
|
||||
"files": [
|
||||
"build/xahau-latest-min.js",
|
||||
"build/xahau-latest-min.js.map",
|
||||
@@ -29,7 +29,7 @@
|
||||
"bignumber.js": "^9.0.0",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"xahau-address-codec": "^5.0.0",
|
||||
"xahau-binary-codec": "^2.1.1",
|
||||
"xahau-binary-codec": "^2.2.0-alpha.0",
|
||||
"xahau-keypairs": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -56,7 +56,7 @@
|
||||
"build:browserTests": "webpack --config ./test/webpack.config.js",
|
||||
"analyze": "webpack --analyze",
|
||||
"watch": "run-s build:lib --watch",
|
||||
"clean": "rm -rf ./dist ./coverage ./test/testCompiledForWeb tsconfig.build.tsbuildinfo",
|
||||
"clean": "rm -rf ./build ./dist ./coverage ./test/testCompiledForWeb tsconfig.build.tsbuildinfo",
|
||||
"docgen": "tsc --build tsconfig.docs.json && typedoc && echo js.xahau.org >> ../../docs/CNAME",
|
||||
"prepare": "copyfiles ../../README.md xahau/README.md",
|
||||
"prepublish": "run-s clean build",
|
||||
|
||||
@@ -355,13 +355,13 @@ export class Wallet {
|
||||
* Output of `sign` includes a `tx_blob` and a `hash`, both of which are needed to submit & verify the results.
|
||||
* Note: If you pass a `Wallet` to `client.submit` or `client.submitAndWait` it will do signing like this under the hood.
|
||||
*
|
||||
* `tx_blob` is a binary representation of a transaction on the XAH Ledger. It's essentially a byte array
|
||||
* `tx_blob` is a binary representation of a transaction on the Xahau Network. It's essentially a byte array
|
||||
* that encodes all of the data necessary to execute the transaction, including the source address, the destination
|
||||
* address, the amount, and any additional fields required for the specific transaction type.
|
||||
*
|
||||
* `hash` is a unique identifier that's generated from the signed transaction data on the XAH Ledger. It's essentially
|
||||
* `hash` is a unique identifier that's generated from the signed transaction data on the Xahau Network. It's essentially
|
||||
* A cryptographic digest of the signed transaction blob, created using a hash function. The signed transaction hash is
|
||||
* Useful for identifying and tracking specific transactions on the XAH Ledger. It can be used to query transaction
|
||||
* Useful for identifying and tracking specific transactions on the Xahau Network. It can be used to query transaction
|
||||
* Information, verify the authenticity of a transaction, and detect any tampering with the transaction data.
|
||||
*
|
||||
* @param this - Wallet instance.
|
||||
|
||||
@@ -40,8 +40,13 @@ import type {
|
||||
MarkerRequest,
|
||||
MarkerResponse,
|
||||
SubmitResponse,
|
||||
SimulateRequest,
|
||||
} from '../models/methods'
|
||||
import type { BookOffer, BookOfferCurrency } from '../models/methods/bookOffers'
|
||||
import {
|
||||
SimulateBinaryResponse,
|
||||
SimulateJsonResponse,
|
||||
} from '../models/methods/simulate'
|
||||
import type {
|
||||
EventTypes,
|
||||
OnEventToListenerMap,
|
||||
@@ -655,7 +660,7 @@ class Client extends EventEmitter<EventTypes> {
|
||||
* @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,
|
||||
@@ -676,6 +681,34 @@ class Client extends EventEmitter<EventTypes> {
|
||||
promises.push(setLatestValidatedLedgerSequence(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
|
||||
}
|
||||
|
||||
await Promise.all(promises).then(() => tx)
|
||||
|
||||
if (tx.Fee == null) {
|
||||
@@ -734,6 +767,41 @@ class Client extends EventEmitter<EventTypes> {
|
||||
return submitRequest(this, signedTx, opts?.failHard)
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates an unsigned transaction.
|
||||
* Steps performed on a transaction:
|
||||
* 1. Autofill.
|
||||
* 2. Sign & Encode.
|
||||
* 3. Submit.
|
||||
*
|
||||
* @category Core
|
||||
*
|
||||
* @param transaction - A transaction to autofill, sign & encode, and submit.
|
||||
* @param opts - (Optional) Options used to sign and submit a transaction.
|
||||
* @param opts.binary - If true, return the metadata in a binary encoding.
|
||||
*
|
||||
* @returns A promise that contains SimulateResponse.
|
||||
* @throws RippledError if the simulate request fails.
|
||||
*/
|
||||
|
||||
public async simulate<Binary extends boolean = false>(
|
||||
transaction: SubmittableTransaction | string,
|
||||
opts?: {
|
||||
// If true, return the binary-encoded representation of the results.
|
||||
binary?: Binary
|
||||
},
|
||||
): Promise<
|
||||
Binary extends true ? SimulateBinaryResponse : SimulateJsonResponse
|
||||
> {
|
||||
// send request
|
||||
const binary = opts?.binary ?? false
|
||||
const request: SimulateRequest =
|
||||
typeof transaction === 'string'
|
||||
? { command: 'simulate', tx_blob: transaction, binary }
|
||||
: { command: 'simulate', tx_json: transaction, binary }
|
||||
return this.request(request)
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously submits a transaction and verifies that it has been included in a
|
||||
* validated ledger (or has errored/will not be included for some reason).
|
||||
@@ -1063,7 +1131,7 @@ class Client extends EventEmitter<EventTypes> {
|
||||
|
||||
/**
|
||||
* The fundWallet() method is used to send an amount of XAH (usually 1000) to a new (randomly generated)
|
||||
* or existing XAH Ledger wallet.
|
||||
* or existing Xahau Network wallet.
|
||||
*
|
||||
* @category Faucet
|
||||
*
|
||||
|
||||
@@ -64,10 +64,11 @@ function isPartialPayment(
|
||||
}
|
||||
|
||||
const delivered = meta.delivered_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
|
||||
const amount = tx.DeliverMax ?? tx.Amount
|
||||
|
||||
if (delivered === undefined) {
|
||||
return false
|
||||
|
||||
@@ -71,7 +71,7 @@ export interface SignerEntry {
|
||||
*/
|
||||
SignerEntry: {
|
||||
/**
|
||||
* An XAH Ledger address whose signature contributes to the multi-signature.
|
||||
* An Xahau Network address whose signature contributes to the multi-signature.
|
||||
* It does not need to be a funded address in the ledger.
|
||||
*/
|
||||
Account: string
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
import { Amount } from '.'
|
||||
|
||||
/**
|
||||
* Enum representing values for Hook Flags for SetHook Transaction.
|
||||
*
|
||||
* @category Transaction Flags
|
||||
*/
|
||||
export enum HookFlags {
|
||||
/**
|
||||
*/
|
||||
hsfOverride = 0x00000001,
|
||||
/**
|
||||
*/
|
||||
hsfNSDelete = 0x0000002,
|
||||
/**
|
||||
*/
|
||||
hsfCollect = 0x00000004,
|
||||
}
|
||||
|
||||
export interface HookFlagsInterface {
|
||||
hsfOverride?: boolean
|
||||
hsfNSDelete?: boolean
|
||||
hsfCollect?: boolean
|
||||
}
|
||||
|
||||
export interface AmountEntry {
|
||||
AmountEntry: { Amount: Amount }
|
||||
}
|
||||
@@ -58,11 +81,19 @@ export interface Hook {
|
||||
/**
|
||||
* The flags that are set on the hook.
|
||||
*/
|
||||
Flags?: number
|
||||
Flags?: number | HookFlagsInterface
|
||||
/**
|
||||
* The transactions that triggers the hook. Represented as a 256Hash
|
||||
*/
|
||||
HookOn?: string
|
||||
/**
|
||||
* The incoming transactions that triggers to the hook. Represented as a 256Hash
|
||||
*/
|
||||
HookOnIncoming?: string
|
||||
/**
|
||||
* The outgoing transactions that triggers from the hook. Represented as a 256Hash
|
||||
*/
|
||||
HookOnOutgoing?: string
|
||||
/**
|
||||
* The transactions that can emit from the hook. Represented as a 256Hash
|
||||
*/
|
||||
@@ -83,6 +114,10 @@ export interface Hook {
|
||||
* The grants of the hook.
|
||||
*/
|
||||
HookGrants?: HookGrant[]
|
||||
/**
|
||||
* The name of the hook.
|
||||
*/
|
||||
HookName?: string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +133,14 @@ export interface EmitDetails {
|
||||
sfEmitCallback?: string
|
||||
}
|
||||
|
||||
export enum MintURITokenFlags {
|
||||
tfBurnable = 0x00000001,
|
||||
}
|
||||
|
||||
export interface MintURITokenFlagsInterface {
|
||||
tfBurnable?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* The object that describes the uritoken in MintURIToken.
|
||||
*/
|
||||
@@ -113,5 +156,5 @@ export interface MintURIToken {
|
||||
/**
|
||||
* The flags that are set on the uritoken.
|
||||
*/
|
||||
Flags?: number
|
||||
Flags?: number | MintURITokenFlagsInterface
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@ export default interface AccountRoot extends BaseLedgerEntry, HasPreviousTxnID {
|
||||
GovernanceMarks?: string
|
||||
AccountIndex?: number
|
||||
TouchCount?: number
|
||||
HookStateScale?: number
|
||||
/* The cron job that is associated with this account. */
|
||||
Cron?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,6 +200,10 @@ export enum AccountRootFlags {
|
||||
* (It has DepositAuth enabled.)
|
||||
*/
|
||||
lsfDepositAuth = 0x01000000,
|
||||
/**
|
||||
* The TSH pays for the execution of their own Hook Chain. Added by the Hooks amendment.
|
||||
*/
|
||||
lsfTshCollect = 0x02000000,
|
||||
/**
|
||||
* Disallow incoming NFTOffers from other accounts.
|
||||
*/
|
||||
|
||||
25
packages/xahau/src/models/ledger/Cron.ts
Normal file
25
packages/xahau/src/models/ledger/Cron.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Account } from '../transactions/common'
|
||||
|
||||
import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'
|
||||
|
||||
/**
|
||||
* The EmittedTxn object type contains the
|
||||
*
|
||||
* @category Ledger Entries
|
||||
*/
|
||||
export default interface Cron extends BaseLedgerEntry, HasPreviousTxnID {
|
||||
LedgerEntryType: 'Cron'
|
||||
/** The owner of the cron job. */
|
||||
Owner: Account
|
||||
/** The start time of the cron job. */
|
||||
StartTime: number
|
||||
/** The delay seconds of the cron job. */
|
||||
DelaySeconds: number
|
||||
/** The repeat count of the cron job. */
|
||||
RepeatCount: number
|
||||
/**
|
||||
* A hint indicating which page of the sender's owner directory links to this
|
||||
* object, in case the directory consists of multiple pages.
|
||||
*/
|
||||
OwnerNode: string
|
||||
}
|
||||
@@ -11,7 +11,7 @@ export interface FeeSettingsPreAmendmentFields {
|
||||
BaseFee: string
|
||||
/** The BaseFee translated into "fee units". */
|
||||
ReferenceFeeUnits: number
|
||||
/** The base reserve for an account in the XAH Ledger, as drops of XAH. */
|
||||
/** The base reserve for an account in the Xahau Network, as drops of XAH. */
|
||||
ReserveBase: number
|
||||
/** The incremental owner reserve for owning objects, as drops of XAH. */
|
||||
ReserveIncrement: number
|
||||
@@ -20,7 +20,7 @@ export interface FeeSettingsPreAmendmentFields {
|
||||
export interface FeeSettingsPostAmendmentFields {
|
||||
/** The transaction cost of the "reference transaction" in drops of XAH as hexadecimal. */
|
||||
BaseFeeDrops: string
|
||||
/** The base reserve for an account in the XAH Ledger, as drops of XAH. */
|
||||
/** The base reserve for an account in the Xahau Network, as drops of XAH. */
|
||||
ReserveBaseDrops: string
|
||||
/** The incremental owner reserve for owning objects, as drops of XAH. */
|
||||
ReserveIncrementDrops: string
|
||||
|
||||
@@ -27,6 +27,16 @@ export default interface HookDefintion
|
||||
*/
|
||||
HookOn?: string
|
||||
|
||||
/**
|
||||
* The incoming transactions that triggers to the hook. Represented as a 256Hash
|
||||
*/
|
||||
HookOnIncoming?: string
|
||||
|
||||
/**
|
||||
* The outgoing transactions that triggers from the hook. Represented as a 256Hash
|
||||
*/
|
||||
HookOnOutgoing?: string
|
||||
|
||||
/**
|
||||
* The namespace of the hook.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import AccountRoot from './AccountRoot'
|
||||
import Amendments from './Amendments'
|
||||
import Check from './Check'
|
||||
import Cron from './Cron'
|
||||
import DepositPreauth from './DepositPreauth'
|
||||
import DirectoryNode from './DirectoryNode'
|
||||
import EmittedTxn from './EmittedTxn'
|
||||
@@ -13,6 +14,7 @@ import ImportVLSequence from './ImportVLSequence'
|
||||
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 @@ import URIToken from './URIToken'
|
||||
type LedgerEntry =
|
||||
| AccountRoot
|
||||
| Amendments
|
||||
| Cron
|
||||
| Check
|
||||
| DepositPreauth
|
||||
| DirectoryNode
|
||||
@@ -36,6 +39,7 @@ type LedgerEntry =
|
||||
| LedgerHashes
|
||||
| NegativeUNL
|
||||
| Offer
|
||||
| Oracle
|
||||
| PayChannel
|
||||
| RippleState
|
||||
| SignerList
|
||||
@@ -46,6 +50,7 @@ type LedgerEntry =
|
||||
type LedgerEntryFilter =
|
||||
| 'account'
|
||||
| 'amendments'
|
||||
| 'cron'
|
||||
| 'check'
|
||||
| 'deposit_preauth'
|
||||
| 'directory'
|
||||
@@ -57,6 +62,7 @@ type LedgerEntryFilter =
|
||||
| 'import_vl_sequence'
|
||||
| 'hashes'
|
||||
| 'offer'
|
||||
| 'oracle'
|
||||
| 'payment_channel'
|
||||
| 'signer_list'
|
||||
| 'state'
|
||||
|
||||
43
packages/xahau/src/models/ledger/Oracle.ts
Normal file
43
packages/xahau/src/models/ledger/Oracle.ts
Normal 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
|
||||
}
|
||||
@@ -2,6 +2,13 @@ import { IssuedCurrencyAmount } from '../common'
|
||||
|
||||
import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'
|
||||
|
||||
export interface RippleStateReward {
|
||||
RewardLgrFirst: number
|
||||
RewardLgrLast: number
|
||||
RewardTime: number
|
||||
TrustLineRewardAccumulator: IssuedCurrencyAmount
|
||||
}
|
||||
|
||||
/**
|
||||
* The RippleState object type connects two accounts in a single currency.
|
||||
*
|
||||
@@ -61,6 +68,8 @@ export default interface RippleState extends BaseLedgerEntry, HasPreviousTxnID {
|
||||
* equivalent to 1 billion, or face value.
|
||||
*/
|
||||
HighQualityOut?: number
|
||||
HighReward?: RippleStateReward
|
||||
LowReward?: RippleStateReward
|
||||
}
|
||||
|
||||
export enum RippleStateFlags {
|
||||
|
||||
@@ -4,6 +4,7 @@ import AccountRoot, {
|
||||
} from './AccountRoot'
|
||||
import Amendments, { Majority, AMENDMENTS_ID } from './Amendments'
|
||||
import Check from './Check'
|
||||
import Cron from './Cron'
|
||||
import DepositPreauth from './DepositPreauth'
|
||||
import DirectoryNode from './DirectoryNode'
|
||||
import EmittedTxn from './EmittedTxn'
|
||||
@@ -22,6 +23,7 @@ import { LedgerEntry, LedgerEntryFilter } from './LedgerEntry'
|
||||
import LedgerHashes from './LedgerHashes'
|
||||
import NegativeUNL, { NEGATIVE_UNL_ID } from './NegativeUNL'
|
||||
import Offer, { OfferFlags } from './Offer'
|
||||
import Oracle from './Oracle'
|
||||
import PayChannel from './PayChannel'
|
||||
import RippleState, { RippleStateFlags } from './RippleState'
|
||||
import SignerList, { SignerListFlags } from './SignerList'
|
||||
@@ -36,6 +38,7 @@ export {
|
||||
AMENDMENTS_ID,
|
||||
Amendments,
|
||||
Check,
|
||||
Cron,
|
||||
DepositPreauth,
|
||||
DirectoryNode,
|
||||
EmittedTxn,
|
||||
@@ -58,6 +61,7 @@ export {
|
||||
NegativeUNL,
|
||||
Offer,
|
||||
OfferFlags,
|
||||
Oracle,
|
||||
PayChannel,
|
||||
RippleState,
|
||||
RippleStateFlags,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Amount } from '../common'
|
||||
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
|
||||
|
||||
/**
|
||||
* Represents a payment channel in the XAH Ledger.
|
||||
* Represents a payment channel in the Xahau Network.
|
||||
*/
|
||||
export interface Channel {
|
||||
/** The owner of the channel, as an Address. */
|
||||
@@ -38,7 +38,7 @@ export interface Channel {
|
||||
settle_delay: number
|
||||
|
||||
/**
|
||||
* The public key for the payment channel in the XAH Ledger's base58 format.
|
||||
* The public key for the payment channel in the Xahau Network's base58 format.
|
||||
* Signed claims against this channel must be redeemed with the matching key pair.
|
||||
*/
|
||||
public_key?: string
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface AccountCurrenciesRequest
|
||||
/** A unique identifier for the account, most commonly the account's address. */
|
||||
account: string
|
||||
/**
|
||||
* If true, then the account field only accepts a public key or XAH Ledger
|
||||
* If true, then the account field only accepts a public key or Xahau Network
|
||||
* address. Otherwise, account can be a secret or passphrase (not
|
||||
* recommended). The default is false.
|
||||
*/
|
||||
|
||||
@@ -25,7 +25,7 @@ export interface AccountInfoRequest extends BaseRequest, LookupByLedgerRequest {
|
||||
*/
|
||||
signer_lists?: boolean
|
||||
/**
|
||||
* If true, then the account field only accepts a public key or XAH Ledger
|
||||
* If true, then the account field only accepts a public key or Xahau Network
|
||||
* address. Otherwise, account can be a secret or passphrase (not
|
||||
* recommended). The default is false.
|
||||
*/
|
||||
@@ -159,7 +159,7 @@ interface BaseAccountInfoResponse extends BaseResponse {
|
||||
/**
|
||||
* Information about queued transactions sent by this account. This
|
||||
* information describes the state of the local xahaud server, which may be
|
||||
* different from other servers in the peer-to-peer XAH Ledger network. Some
|
||||
* different from other servers in the peer-to-peer Xahau Network network. Some
|
||||
* fields may be omitted because the values are calculated "lazily" by the
|
||||
* queuing mechanism.
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,7 @@ export interface AccountOffersRequest
|
||||
*/
|
||||
marker?: unknown
|
||||
/**
|
||||
* If true, then the account field only accepts a public key or XAH Ledger
|
||||
* If true, then the account field only accepts a public key or Xahau Network
|
||||
* address. Otherwise, account can be a secret or passphrase (not
|
||||
* recommended). The default is false.
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,7 @@ export interface ChannelVerifyRequest extends BaseRequest {
|
||||
channel_id: string
|
||||
/**
|
||||
* The public key of the channel and the key pair that was used to create the
|
||||
* signature, in hexadecimal or the XAH Ledger's base58 format.
|
||||
* signature, in hexadecimal or the Xahau Network's base58 format.
|
||||
*/
|
||||
public_key: string
|
||||
/** The signature to verify, in hexadecimal. */
|
||||
|
||||
119
packages/xahau/src/models/methods/getAggregatePrice.ts
Normal file
119
packages/xahau/src/models/methods/getAggregatePrice.ts
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,10 @@ import {
|
||||
GatewayBalancesRequest,
|
||||
GatewayBalancesResponse,
|
||||
} from './gatewayBalances'
|
||||
import {
|
||||
GetAggregatePriceRequest,
|
||||
GetAggregatePriceResponse,
|
||||
} from './getAggregatePrice'
|
||||
import {
|
||||
LedgerBinary,
|
||||
LedgerModifiedOfferCreateTransaction,
|
||||
@@ -133,6 +137,14 @@ import {
|
||||
StateAccountingFinal,
|
||||
} from './serverInfo'
|
||||
import { ServerStateRequest, ServerStateResponse } from './serverState'
|
||||
import {
|
||||
SimulateBinaryRequest,
|
||||
SimulateBinaryResponse,
|
||||
SimulateJsonRequest,
|
||||
SimulateJsonResponse,
|
||||
SimulateRequest,
|
||||
SimulateResponse,
|
||||
} from './simulate'
|
||||
import { SubmitRequest, SubmitResponse } from './submit'
|
||||
import {
|
||||
SubmitMultisignedRequest,
|
||||
@@ -188,6 +200,7 @@ type Request =
|
||||
| LedgerDataRequest
|
||||
| LedgerEntryRequest
|
||||
// transaction methods
|
||||
| SimulateRequest
|
||||
| SubmitRequest
|
||||
| SubmitMultisignedRequest
|
||||
| TransactionEntryRequest
|
||||
@@ -212,6 +225,8 @@ type Request =
|
||||
// utility methods
|
||||
| PingRequest
|
||||
| RandomRequest
|
||||
// Price Oracle methods
|
||||
| GetAggregatePriceRequest
|
||||
|
||||
/**
|
||||
* @category Responses
|
||||
@@ -235,6 +250,7 @@ type Response<Version extends APIVersion = typeof DEFAULT_API_VERSION> =
|
||||
| LedgerDataResponse
|
||||
| LedgerEntryResponse
|
||||
// transaction methods
|
||||
| SimulateResponse
|
||||
| SubmitResponse
|
||||
| SubmitMultisignedVersionResponseMap<Version>
|
||||
| TransactionEntryResponse
|
||||
@@ -259,6 +275,8 @@ type Response<Version extends APIVersion = typeof DEFAULT_API_VERSION> =
|
||||
// utility methods
|
||||
| PingResponse
|
||||
| RandomResponse
|
||||
// Price Oracle methods
|
||||
| GetAggregatePriceResponse
|
||||
|
||||
export type RequestResponseMap<
|
||||
T,
|
||||
@@ -279,6 +297,8 @@ export type RequestResponseMap<
|
||||
? AccountTxVersionResponseMap<Version>
|
||||
: T extends GatewayBalancesRequest
|
||||
? GatewayBalancesResponse
|
||||
: T extends GetAggregatePriceRequest
|
||||
? GetAggregatePriceResponse
|
||||
: T extends NoRippleCheckRequest
|
||||
? NoRippleCheckResponse
|
||||
: // NOTE: The order of these LedgerRequest types is important
|
||||
@@ -355,6 +375,12 @@ export type RequestResponseMap<
|
||||
? LedgerDataResponse
|
||||
: T extends LedgerEntryRequest
|
||||
? LedgerEntryResponse
|
||||
: T extends SimulateBinaryRequest
|
||||
? SimulateBinaryResponse
|
||||
: T extends SimulateJsonRequest
|
||||
? SimulateJsonResponse
|
||||
: T extends SimulateRequest
|
||||
? SimulateJsonResponse
|
||||
: T extends SubmitRequest
|
||||
? SubmitResponse
|
||||
: T extends SubmitMultisignedRequest
|
||||
@@ -465,6 +491,8 @@ export {
|
||||
GatewayBalance,
|
||||
GatewayBalancesRequest,
|
||||
GatewayBalancesResponse,
|
||||
GetAggregatePriceRequest,
|
||||
GetAggregatePriceResponse,
|
||||
NoRippleCheckRequest,
|
||||
NoRippleCheckResponse,
|
||||
// ledger methods
|
||||
@@ -486,6 +514,8 @@ export {
|
||||
LedgerEntryRequest,
|
||||
LedgerEntryResponse,
|
||||
// transaction methods with types
|
||||
SimulateRequest,
|
||||
SimulateResponse,
|
||||
SubmitRequest,
|
||||
SubmitResponse,
|
||||
SubmitMultisignedRequest,
|
||||
|
||||
@@ -203,13 +203,13 @@ export interface LedgerQueueData {
|
||||
}
|
||||
|
||||
export interface LedgerBinary
|
||||
extends Omit<Omit<Ledger, 'transactions'>, 'accountState'> {
|
||||
extends Omit<Ledger, 'transactions' | 'accountState'> {
|
||||
accountState?: string[]
|
||||
transactions?: string[]
|
||||
}
|
||||
|
||||
export interface LedgerBinaryV1
|
||||
extends Omit<Omit<LedgerV1, 'transactions'>, 'accountState'> {
|
||||
extends Omit<LedgerV1, 'transactions' | 'accountState'> {
|
||||
accountState?: string[]
|
||||
transactions?: string[]
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { LedgerEntry } from '../ledger'
|
||||
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
|
||||
|
||||
/**
|
||||
* The `ledger_entry` method returns a single ledger object from the XAH Ledger
|
||||
* The `ledger_entry` method returns a single ledger object from the Xahau Network
|
||||
* in its raw format. Expects a response in the form of a {@link
|
||||
* LedgerEntryResponse}.
|
||||
*
|
||||
@@ -30,7 +30,7 @@ export interface LedgerEntryRequest extends BaseRequest, LookupByLedgerRequest {
|
||||
include_deleted?: boolean
|
||||
/**
|
||||
* If true, return the requested ledger object's contents as a hex string in
|
||||
* the XAH Ledger's binary format. Otherwise, return data in JSON format. The
|
||||
* the Xahau Network's binary format. Otherwise, return data in JSON format. The
|
||||
* default is false.
|
||||
*/
|
||||
binary?: boolean
|
||||
@@ -200,6 +200,20 @@ export interface LedgerEntryRequest extends BaseRequest, LookupByLedgerRequest {
|
||||
uri: string
|
||||
}
|
||||
| string
|
||||
|
||||
/**
|
||||
* The Cron object to retrieve. If a string, must be the object ID of the
|
||||
* Cron, as hexadecimal. If an object, the `owner` and `time`
|
||||
* sub-fields are required to uniquely specify the Cron entry.
|
||||
*/
|
||||
cron?:
|
||||
| {
|
||||
/** The owner of the Cron object. */
|
||||
owner: string
|
||||
/** The start time of the Cron object. */
|
||||
time: number
|
||||
}
|
||||
| string
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -108,7 +108,7 @@ export interface ServerInfoResponse extends BaseResponse {
|
||||
* The number of times (since starting up) that this server has had over
|
||||
* 250 transactions waiting to be processed at once. A large number here
|
||||
* may mean that your server is unable to handle the transaction load of
|
||||
* the XAH Ledger network.
|
||||
* the Xahau Network network.
|
||||
*/
|
||||
jq_trans_overflow: string
|
||||
/**
|
||||
|
||||
88
packages/xahau/src/models/methods/simulate.ts
Normal file
88
packages/xahau/src/models/methods/simulate.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import {
|
||||
BaseTransaction,
|
||||
Transaction,
|
||||
TransactionMetadata,
|
||||
} from '../transactions'
|
||||
|
||||
import { BaseRequest, BaseResponse } from './baseMethod'
|
||||
|
||||
/**
|
||||
* The `simulate` method simulates a transaction without submitting it to the network.
|
||||
* Returns a {@link SimulateResponse}.
|
||||
*
|
||||
* @category Requests
|
||||
*/
|
||||
export type SimulateRequest = BaseRequest & {
|
||||
command: 'simulate'
|
||||
|
||||
binary?: boolean
|
||||
} & (
|
||||
| {
|
||||
tx_blob: string
|
||||
tx_json?: never
|
||||
}
|
||||
| {
|
||||
tx_json: Transaction
|
||||
tx_blob?: never
|
||||
}
|
||||
)
|
||||
|
||||
export type SimulateBinaryRequest = SimulateRequest & {
|
||||
binary: true
|
||||
}
|
||||
|
||||
export type SimulateJsonRequest = SimulateRequest & {
|
||||
binary?: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Response expected from an {@link SimulateRequest}.
|
||||
*
|
||||
* @category Responses
|
||||
*/
|
||||
export type SimulateResponse = SimulateJsonResponse | SimulateBinaryResponse
|
||||
|
||||
export interface SimulateBinaryResponse extends BaseResponse {
|
||||
result: {
|
||||
applied: false
|
||||
|
||||
engine_result: string
|
||||
|
||||
engine_result_code: number
|
||||
|
||||
engine_result_message: string
|
||||
|
||||
tx_blob: string
|
||||
|
||||
meta_blob: string
|
||||
|
||||
/**
|
||||
* The ledger index of the ledger version that was used to generate this
|
||||
* response.
|
||||
*/
|
||||
ledger_index: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface SimulateJsonResponse<T extends BaseTransaction = Transaction>
|
||||
extends BaseResponse {
|
||||
result: {
|
||||
applied: false
|
||||
|
||||
engine_result: string
|
||||
|
||||
engine_result_code: number
|
||||
|
||||
engine_result_message: string
|
||||
|
||||
/**
|
||||
* The ledger index of the ledger version that was used to generate this
|
||||
* response.
|
||||
*/
|
||||
ledger_index: number
|
||||
|
||||
tx_json: T
|
||||
|
||||
meta?: TransactionMetadata<T>
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ export interface SubmitResponse extends BaseResponse {
|
||||
applied: boolean
|
||||
/**
|
||||
* The value true indicates this transaction was broadcast to peer servers
|
||||
* in the peer-to-peer XAH Ledger network.
|
||||
* in the peer-to-peer Xahau Network network.
|
||||
*/
|
||||
broadcast: boolean
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface SubscribeBook {
|
||||
taker_pays: Currency
|
||||
/**
|
||||
* Unique account address to use as a perspective for viewing offers, in the.
|
||||
* XAH Ledger's base58 format.
|
||||
* Xahau Network's base58 format.
|
||||
*/
|
||||
taker: string
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ export interface SubscribeRequest extends BaseRequest {
|
||||
streams?: StreamType[]
|
||||
/**
|
||||
* Array with the unique addresses of accounts to monitor for validated
|
||||
* transactions. The addresses must be in the XAH Ledger's base58 format.
|
||||
* transactions. The addresses must be in the Xahau Network's base58 format.
|
||||
* The server sends a notification for any transaction that affects at least
|
||||
* one of these accounts.
|
||||
*/
|
||||
@@ -235,7 +235,7 @@ export interface ValidationStream extends BaseStream {
|
||||
load_fee?: number
|
||||
/**
|
||||
* The validator's master public key, if the validator is using a validator
|
||||
* token, in the XAH Ledger's base58 format.
|
||||
* token, in the Xahau Network's base58 format.
|
||||
*/
|
||||
master_key?: string
|
||||
/**
|
||||
@@ -254,7 +254,7 @@ export interface ValidationStream extends BaseStream {
|
||||
signing_time: number
|
||||
/**
|
||||
* The public key from the key-pair that the validator used to sign the
|
||||
* message, in the XAH Ledger's base58 format. This identifies the validator
|
||||
* message, in the Xahau Network's base58 format. This identifies the validator
|
||||
* sending the message and can also be used to verify the signature. If the
|
||||
* validator is using a token, this is an ephemeral public key.
|
||||
*/
|
||||
|
||||
@@ -24,7 +24,7 @@ export interface UnsubscribeRequest extends BaseRequest {
|
||||
streams?: StreamType[]
|
||||
/**
|
||||
* Array of unique account addresses to stop receiving updates for, in the.
|
||||
* XAH Ledger's base58 format.
|
||||
* Xahau Network's base58 format.
|
||||
*/
|
||||
accounts?: string[]
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
Account,
|
||||
BaseTransaction,
|
||||
isAccount,
|
||||
isNumber,
|
||||
validateBaseTransaction,
|
||||
validateOptionalField,
|
||||
} from './common'
|
||||
@@ -163,10 +164,16 @@ export interface AccountSet extends BaseTransaction {
|
||||
* account's behalf using NFTokenMint's `Issuer` field.
|
||||
*/
|
||||
NFTokenMinter?: Account
|
||||
/**
|
||||
* The allowed scale of the hook state.
|
||||
*/
|
||||
HookStateScale?: number
|
||||
}
|
||||
|
||||
const MIN_TICK_SIZE = 3
|
||||
const MAX_TICK_SIZE = 15
|
||||
const MAX_HOOK_STATE_SCALE = 16
|
||||
const MIN_HOOK_STATE_SCALE = 1
|
||||
|
||||
/**
|
||||
* Verify the form and type of an AccountSet at runtime.
|
||||
@@ -174,7 +181,7 @@ const MAX_TICK_SIZE = 15
|
||||
* @param tx - An AccountSet Transaction.
|
||||
* @throws When the AccountSet is Malformed.
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function -- okay for this method, only a little over
|
||||
// eslint-disable-next-line max-lines-per-function, max-statements -- okay for this method, only a little over
|
||||
export function validateAccountSet(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
@@ -225,4 +232,24 @@ export function validateAccountSet(tx: Record<string, unknown>): void {
|
||||
throw new ValidationError('AccountSet: invalid TickSize')
|
||||
}
|
||||
}
|
||||
|
||||
validateOptionalField(tx, 'HookStateScale', isNumber)
|
||||
|
||||
if (
|
||||
typeof tx.HookStateScale === 'number' &&
|
||||
tx.HookStateScale > MAX_HOOK_STATE_SCALE
|
||||
) {
|
||||
throw new ValidationError(
|
||||
`AccountSet: HookStateScale must be less than or equal to ${MAX_HOOK_STATE_SCALE}`,
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
typeof tx.HookStateScale === 'number' &&
|
||||
tx.HookStateScale < MIN_HOOK_STATE_SCALE
|
||||
) {
|
||||
throw new ValidationError(
|
||||
`AccountSet: HookStateScale must be greater than or equal to ${MIN_HOOK_STATE_SCALE}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ValidationError } from '../../errors'
|
||||
import { Currency } from '../common'
|
||||
|
||||
import { BaseTransaction, validateBaseTransaction } from './common'
|
||||
import { BaseTransaction, GlobalFlags, validateBaseTransaction } from './common'
|
||||
/**
|
||||
* Transaction Flags for an ClaimReward Transaction.
|
||||
*
|
||||
@@ -13,6 +14,39 @@ export enum ClaimRewardFlags {
|
||||
tfOptOut = 0x00000001,
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of flags to boolean values representing {@link ClaimReward} transaction
|
||||
* flags.
|
||||
*
|
||||
* @category Transaction Flags
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const tx: ClaimReward = {
|
||||
* Account: 'rhFcpWDHLqpBmX4ezWiA5VLSS4e1BHqhHd',
|
||||
* TransactionType: 'ClaimReward',
|
||||
* Flags: {
|
||||
* tfOptOut: true,
|
||||
* },
|
||||
* }
|
||||
*
|
||||
* // Autofill the tx to see how flags actually look compared to the interface usage.
|
||||
* const autofilledTx = await client.autofill(tx)
|
||||
* console.log(autofilledTx)
|
||||
* // {
|
||||
* // Account: 'rhFcpWDHLqpBmX4ezWiA5VLSS4e1BHqhHd',
|
||||
* // TransactionType: 'ClaimReward',
|
||||
* // Flags: 0,
|
||||
* // Sequence: 21970384,
|
||||
* // Fee: '12',
|
||||
* // LastLedgerSequence: 21970404
|
||||
* // }
|
||||
* ```
|
||||
*/
|
||||
export interface ClaimRewardFlagsInterface extends GlobalFlags {
|
||||
tfOptOut?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* ClaimReward is a transaction model that allows an account to claim rewards.
|
||||
*
|
||||
@@ -20,9 +54,10 @@ export enum ClaimRewardFlags {
|
||||
*/
|
||||
export interface ClaimReward extends BaseTransaction {
|
||||
TransactionType: 'ClaimReward'
|
||||
Flags?: number | ClaimRewardFlags
|
||||
Flags?: number | ClaimRewardFlagsInterface
|
||||
/** The unique address of the issuer where the reward.c hook is installed. */
|
||||
Issuer?: string
|
||||
ClaimCurrency?: Currency
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -275,6 +275,10 @@ export interface BaseTransaction {
|
||||
* The hook parameters of the transaction.
|
||||
*/
|
||||
HookParameters?: HookParameter[]
|
||||
/**
|
||||
* The name of the hooks triggered by the transaction.
|
||||
*/
|
||||
HookName?: string
|
||||
/**
|
||||
* The hook parameters of the transaction.
|
||||
*/
|
||||
|
||||
17
packages/xahau/src/models/transactions/cron.ts
Normal file
17
packages/xahau/src/models/transactions/cron.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { BaseTransaction } from './common'
|
||||
|
||||
/**
|
||||
* Cron job to be executed.
|
||||
*
|
||||
* @category Pseudo Transaction Models
|
||||
*/
|
||||
export interface Cron extends BaseTransaction {
|
||||
TransactionType: 'Cron'
|
||||
/**
|
||||
* The ledger index where this pseudo-transaction appears.
|
||||
* This distinguishes the pseudo-transaction from other occurrences of the same change.
|
||||
*/
|
||||
LedgerSequence: number
|
||||
/** The owner of the cron job. */
|
||||
Owner: string
|
||||
}
|
||||
123
packages/xahau/src/models/transactions/cronSet.ts
Normal file
123
packages/xahau/src/models/transactions/cronSet.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { ValidationError } from '../../errors'
|
||||
|
||||
import {
|
||||
BaseTransaction,
|
||||
GlobalFlags,
|
||||
isNumber,
|
||||
validateBaseTransaction,
|
||||
validateOptionalField,
|
||||
validateRequiredField,
|
||||
} from './common'
|
||||
/**
|
||||
* Transaction Flags for an CronSet Transaction.
|
||||
*
|
||||
* @category Transaction Flags
|
||||
*/
|
||||
export enum CronSetFlags {
|
||||
/**
|
||||
* If set, indicates that the user would like to unset the cron job.
|
||||
*/
|
||||
tfCronUnset = 0x00000001,
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of flags to boolean values representing {@link CronSet} transaction
|
||||
* flags.
|
||||
*
|
||||
* @category Transaction Flags
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const tx: CronSet = {
|
||||
* Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
* TransactionType: 'CronSet',
|
||||
* Flags: {
|
||||
* tfCronUnset: true,
|
||||
* },
|
||||
* }
|
||||
*
|
||||
* // Autofill the tx to see how flags actually look compared to the interface usage.
|
||||
* const autofilledTx = await client.autofill(tx)
|
||||
* console.log(autofilledTx)
|
||||
* // {
|
||||
* // Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
* // TransactionType: 'CronSet',
|
||||
* // Flags: 0,
|
||||
* // Sequence: 21970384,
|
||||
* // Fee: '12',
|
||||
* // LastLedgerSequence: 21970404
|
||||
* // }
|
||||
* ```
|
||||
*/
|
||||
export interface CronSetFlagsInterface extends GlobalFlags {
|
||||
tfCronUnset?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* CronSet is a transaction model that allows an account to set a cron job.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface CronSet extends BaseTransaction {
|
||||
TransactionType: 'CronSet'
|
||||
Flags?: number | CronSetFlagsInterface
|
||||
RepeatCount?: number
|
||||
DelaySeconds?: number
|
||||
StartTime?: number
|
||||
}
|
||||
|
||||
const MAX_REPEAT_COUNT = 256
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- seconds in a year
|
||||
const MIN_DELAY_SECONDS = 365 * 24 * 60 * 60
|
||||
|
||||
/**
|
||||
* Verify the form and type of an CronSet at runtime.
|
||||
*
|
||||
* @param tx - An CronSet Transaction.
|
||||
* @throws When the CronSet is Malformed.
|
||||
*/
|
||||
export function validateCronSet(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
if (
|
||||
typeof tx.Flags === 'number' &&
|
||||
// eslint-disable-next-line no-bitwise -- bitwise operation to check if the flag is set
|
||||
tx.Flags & CronSetFlags.tfCronUnset
|
||||
) {
|
||||
if (
|
||||
tx.RepeatCount !== undefined ||
|
||||
tx.DelaySeconds !== undefined ||
|
||||
tx.StartTime !== undefined
|
||||
) {
|
||||
throw new ValidationError(
|
||||
'CronSet: RepeatCount, DelaySeconds, and StartTime must not be set when Flags is set to tfCronUnset',
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
validateRequiredField(tx, 'StartTime', isNumber)
|
||||
validateOptionalField(tx, 'RepeatCount', isNumber)
|
||||
validateOptionalField(tx, 'DelaySeconds', isNumber)
|
||||
|
||||
if ((tx.RepeatCount === undefined) !== (tx.DelaySeconds === undefined)) {
|
||||
throw new ValidationError(
|
||||
'CronSet: Both RepeatCount and DelaySeconds must be set, or neither should be set',
|
||||
)
|
||||
}
|
||||
|
||||
if (typeof tx.RepeatCount === 'number' && tx.RepeatCount > MAX_REPEAT_COUNT) {
|
||||
throw new ValidationError(
|
||||
`CronSet: RepeatCount must be less than ${MAX_REPEAT_COUNT}`,
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
typeof tx.DelaySeconds === 'number' &&
|
||||
tx.DelaySeconds > MIN_DELAY_SECONDS
|
||||
) {
|
||||
throw new ValidationError(
|
||||
`CronSet: DelaySeconds must be less than ${MIN_DELAY_SECONDS}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,10 @@ import { BaseTransaction, validateBaseTransaction } from './common'
|
||||
*/
|
||||
export interface DepositPreauth extends BaseTransaction {
|
||||
TransactionType: 'DepositPreauth'
|
||||
/** The XAH Ledger address of the sender to preauthorize. */
|
||||
/** The Xahau Network address of the sender to preauthorize. */
|
||||
Authorize?: string
|
||||
/**
|
||||
* The XAH Ledger address of a sender whose preauthorization should be.
|
||||
* The Xahau Network address of a sender whose preauthorization should be.
|
||||
* revoked.
|
||||
*/
|
||||
Unauthorize?: string
|
||||
|
||||
@@ -17,6 +17,8 @@ export { CheckCancel } from './checkCancel'
|
||||
export { CheckCash } from './checkCash'
|
||||
export { CheckCreate } from './checkCreate'
|
||||
export { ClaimReward, ClaimRewardFlags } from './claimReward'
|
||||
export { Cron } from './cron'
|
||||
export { CronSet, CronSetFlags } from './cronSet'
|
||||
export { DepositPreauth } from './depositPreauth'
|
||||
export { EscrowCancel } from './escrowCancel'
|
||||
export { EscrowCreate } from './escrowCreate'
|
||||
@@ -30,6 +32,8 @@ export {
|
||||
OfferCreateFlagsInterface,
|
||||
OfferCreate,
|
||||
} from './offerCreate'
|
||||
export { OracleDelete } from './oracleDelete'
|
||||
export { OracleSet } from './oracleSet'
|
||||
export { PaymentFlags, PaymentFlagsInterface, Payment } from './payment'
|
||||
export {
|
||||
PaymentChannelClaimFlags,
|
||||
@@ -39,7 +43,7 @@ export {
|
||||
export { PaymentChannelCreate } from './paymentChannelCreate'
|
||||
export { PaymentChannelFund } from './paymentChannelFund'
|
||||
export { Remit } from './remit'
|
||||
export { SetHookFlagsInterface, SetHookFlags, SetHook } from './setHook'
|
||||
export { SetHook } from './setHook'
|
||||
export { SetFee, SetFeePreAmendment, SetFeePostAmendment } from './setFee'
|
||||
export { SetRegularKey } from './setRegularKey'
|
||||
export {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ValidationError } from '../../errors'
|
||||
import { BaseTransaction, validateBaseTransaction } from './common'
|
||||
|
||||
/**
|
||||
* An OfferCancel transaction removes an Offer object from the XAH Ledger.
|
||||
* An OfferCancel transaction removes an Offer object from the Xahau Network.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
|
||||
32
packages/xahau/src/models/transactions/oracleDelete.ts
Normal file
32
packages/xahau/src/models/transactions/oracleDelete.ts
Normal 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)
|
||||
}
|
||||
198
packages/xahau/src/models/transactions/oracleSet.ts
Normal file
198
packages/xahau/src/models/transactions/oracleSet.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
import { ValidationError } from '../../errors'
|
||||
import { PriceData } from '../common'
|
||||
import { isHex } from '../utils'
|
||||
|
||||
import {
|
||||
BaseTransaction,
|
||||
isNumber,
|
||||
isString,
|
||||
validateBaseTransaction,
|
||||
validateOptionalField,
|
||||
validateRequiredField,
|
||||
} from './common'
|
||||
|
||||
const PRICE_DATA_SERIES_MAX_LENGTH = 10
|
||||
const SCALE_MAX = 10
|
||||
const MINIMUM_ASSET_PRICE_LENGTH = 1
|
||||
const MAXIMUM_ASSET_PRICE_LENGTH = 16
|
||||
|
||||
/**
|
||||
* Creates a new Oracle ledger entry or updates the fields of an existing one, using the Oracle ID.
|
||||
*
|
||||
* The oracle provider must complete these steps before submitting this transaction:
|
||||
* 1. Create or own the XRPL account in the Owner field and have enough XRP to meet the reserve and transaction fee requirements.
|
||||
* 2. Publish the XRPL account public key, so it can be used for verification by dApps.
|
||||
* 3. Publish a registry of available price oracles with their unique OracleDocumentID.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface OracleSet extends BaseTransaction {
|
||||
TransactionType: 'OracleSet'
|
||||
|
||||
/**
|
||||
* A unique identifier of the price oracle for the Account.
|
||||
*/
|
||||
OracleDocumentID: number
|
||||
|
||||
/**
|
||||
* The time the data was last updated, represented as a unix timestamp in seconds.
|
||||
*/
|
||||
LastUpdateTime: number
|
||||
|
||||
/**
|
||||
* An array of up to 10 PriceData objects, each representing the price information
|
||||
* for a token pair. More than five PriceData objects require two owner reserves.
|
||||
*/
|
||||
PriceDataSeries: PriceData[]
|
||||
|
||||
/**
|
||||
* An arbitrary value that identifies an oracle provider, such as Chainlink, Band,
|
||||
* or DIA. This field is a string, up to 256 ASCII hex encoded characters (0x20-0x7E).
|
||||
* This field is required when creating a new Oracle ledger entry, but is optional for updates.
|
||||
*/
|
||||
Provider?: string
|
||||
|
||||
/**
|
||||
* An optional Universal Resource Identifier to reference price data off-chain. This field is limited to 256 bytes.
|
||||
*/
|
||||
URI?: string
|
||||
|
||||
/**
|
||||
* Describes the type of asset, such as "currency", "commodity", or "index". This field is a string, up to 16 ASCII
|
||||
* hex encoded characters (0x20-0x7E). This field is required when creating a new Oracle ledger entry, but is optional
|
||||
* for updates.
|
||||
*/
|
||||
AssetClass?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of a OracleSet at runtime.
|
||||
*
|
||||
* @param tx - A OracleSet Transaction.
|
||||
* @throws When the OracleSet is malformed.
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function -- necessary to validate many fields
|
||||
export function validateOracleSet(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
validateRequiredField(tx, 'OracleDocumentID', isNumber)
|
||||
|
||||
validateRequiredField(tx, 'LastUpdateTime', isNumber)
|
||||
|
||||
validateOptionalField(tx, 'Provider', isString)
|
||||
|
||||
validateOptionalField(tx, 'URI', isString)
|
||||
|
||||
validateOptionalField(tx, 'AssetClass', isString)
|
||||
|
||||
/* eslint-disable max-statements, max-lines-per-function -- necessary to validate many fields */
|
||||
validateRequiredField(tx, 'PriceDataSeries', (value) => {
|
||||
if (!Array.isArray(value)) {
|
||||
throw new ValidationError('OracleSet: PriceDataSeries must be an array')
|
||||
}
|
||||
|
||||
if (value.length > PRICE_DATA_SERIES_MAX_LENGTH) {
|
||||
throw new ValidationError(
|
||||
`OracleSet: PriceDataSeries must have at most ${PRICE_DATA_SERIES_MAX_LENGTH} PriceData objects`,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: add support for handling inner objects easier (similar to validateRequiredField/validateOptionalField)
|
||||
for (const priceData of value) {
|
||||
if (typeof priceData !== 'object') {
|
||||
throw new ValidationError(
|
||||
'OracleSet: PriceDataSeries must be an array of objects',
|
||||
)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
|
||||
if (priceData.PriceData == null) {
|
||||
throw new ValidationError(
|
||||
'OracleSet: PriceDataSeries must have a `PriceData` object',
|
||||
)
|
||||
}
|
||||
|
||||
// check if priceData only has PriceData
|
||||
if (Object.keys(priceData).length !== 1) {
|
||||
throw new ValidationError(
|
||||
'OracleSet: PriceDataSeries must only have a single PriceData object',
|
||||
)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
|
||||
if (typeof priceData.PriceData.BaseAsset !== 'string') {
|
||||
throw new ValidationError(
|
||||
'OracleSet: PriceDataSeries must have a `BaseAsset` string',
|
||||
)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
|
||||
if (typeof priceData.PriceData.QuoteAsset !== 'string') {
|
||||
throw new ValidationError(
|
||||
'OracleSet: PriceDataSeries must have a `QuoteAsset` string',
|
||||
)
|
||||
}
|
||||
|
||||
// Either AssetPrice and Scale are both present or both excluded
|
||||
if (
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
|
||||
(priceData.PriceData.AssetPrice == null) !==
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
|
||||
(priceData.PriceData.Scale == null)
|
||||
) {
|
||||
throw new ValidationError(
|
||||
'OracleSet: PriceDataSeries must have both `AssetPrice` and `Scale` if any are present',
|
||||
)
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access, max-depth --
|
||||
we need to validate priceData.PriceData.AssetPrice value */
|
||||
if ('AssetPrice' in priceData.PriceData) {
|
||||
if (!isNumber(priceData.PriceData.AssetPrice)) {
|
||||
if (typeof priceData.PriceData.AssetPrice !== 'string') {
|
||||
throw new ValidationError(
|
||||
'OracleSet: Field AssetPrice must be a string or a number',
|
||||
)
|
||||
}
|
||||
if (!isHex(priceData.PriceData.AssetPrice)) {
|
||||
throw new ValidationError(
|
||||
'OracleSet: Field AssetPrice must be a valid hex string',
|
||||
)
|
||||
}
|
||||
if (
|
||||
priceData.PriceData.AssetPrice.length <
|
||||
MINIMUM_ASSET_PRICE_LENGTH ||
|
||||
priceData.PriceData.AssetPrice.length > MAXIMUM_ASSET_PRICE_LENGTH
|
||||
) {
|
||||
throw new ValidationError(
|
||||
`OracleSet: Length of AssetPrice field must be between ${MINIMUM_ASSET_PRICE_LENGTH} and ${MAXIMUM_ASSET_PRICE_LENGTH} characters long`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-unsafe-member-access, max-depth */
|
||||
|
||||
if (
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
|
||||
'Scale' in priceData.PriceData &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
|
||||
!isNumber(priceData.PriceData.Scale)
|
||||
) {
|
||||
throw new ValidationError('OracleSet: invalid field Scale')
|
||||
}
|
||||
|
||||
if (
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
|
||||
priceData.PriceData.Scale < 0 ||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
|
||||
priceData.PriceData.Scale > SCALE_MAX
|
||||
) {
|
||||
throw new ValidationError(
|
||||
`OracleSet: Scale must be in range 0-${SCALE_MAX}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
/* eslint-enable max-statements, max-lines-per-function */
|
||||
}
|
||||
@@ -1,30 +1,7 @@
|
||||
import { ValidationError } from '../../errors'
|
||||
import { Hook } from '../common/xahau'
|
||||
|
||||
import { BaseTransaction, GlobalFlags, validateBaseTransaction } from './common'
|
||||
|
||||
/**
|
||||
* Enum representing values for Set Hook Transaction Flags.
|
||||
*
|
||||
* @category Transaction Flags
|
||||
*/
|
||||
export enum SetHookFlags {
|
||||
/**
|
||||
*/
|
||||
hsfOverride = 0x00000001,
|
||||
/**
|
||||
*/
|
||||
hsfNSDelete = 0x0000002,
|
||||
/**
|
||||
*/
|
||||
hsfCollect = 0x00000004,
|
||||
}
|
||||
|
||||
export interface SetHookFlagsInterface extends GlobalFlags {
|
||||
hsfOverride?: boolean
|
||||
hsfNSDelete?: boolean
|
||||
hsfCollect?: boolean
|
||||
}
|
||||
import { BaseTransaction, validateBaseTransaction } from './common'
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -37,12 +14,14 @@ export interface SetHook extends BaseTransaction {
|
||||
*
|
||||
*/
|
||||
Hooks: Hook[]
|
||||
|
||||
Flags?: number | SetHookFlagsInterface
|
||||
}
|
||||
|
||||
const MAX_HOOKS = 10
|
||||
const HEX_REGEX = /^[0-9A-Fa-f]{64}$/u
|
||||
/**
|
||||
* 4-16 bytes in hex
|
||||
*/
|
||||
const HOOKNAME_REGEX = /^[0-9A-Fa-f]{8,32}$/u
|
||||
|
||||
/**
|
||||
* Verify the form and type of an SetHook at runtime.
|
||||
@@ -50,6 +29,7 @@ const HEX_REGEX = /^[0-9A-Fa-f]{64}$/u
|
||||
* @param tx - An SetHook Transaction.
|
||||
* @throws When the SetHook is Malformed.
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function -- okay for this method
|
||||
export function validateSetHook(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
@@ -66,12 +46,29 @@ export function validateSetHook(tx: Record<string, unknown>): void {
|
||||
for (const hook of tx.Hooks) {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Should be a Hook
|
||||
const hookObject = hook as Hook
|
||||
const { HookOn, HookCanEmit, HookNamespace } = hookObject.Hook
|
||||
const {
|
||||
HookOn,
|
||||
HookOnIncoming,
|
||||
HookOnOutgoing,
|
||||
HookCanEmit,
|
||||
HookNamespace,
|
||||
HookName,
|
||||
} = hookObject.Hook
|
||||
if (HookOn !== undefined && !HEX_REGEX.test(HookOn)) {
|
||||
throw new ValidationError(
|
||||
`SetHook: HookOn in Hook must be a 256-bit (32-byte) hexadecimal value`,
|
||||
)
|
||||
}
|
||||
if (HookOnIncoming !== undefined && !HEX_REGEX.test(HookOnIncoming)) {
|
||||
throw new ValidationError(
|
||||
`SetHook: HookOnIncoming in Hook must be a 256-bit (32-byte) hexadecimal value`,
|
||||
)
|
||||
}
|
||||
if (HookOnOutgoing !== undefined && !HEX_REGEX.test(HookOnOutgoing)) {
|
||||
throw new ValidationError(
|
||||
`SetHook: HookOnOutgoing in Hook must be a 256-bit (32-byte) hexadecimal value`,
|
||||
)
|
||||
}
|
||||
if (HookCanEmit !== undefined && !HEX_REGEX.test(HookCanEmit)) {
|
||||
throw new ValidationError(
|
||||
`SetHook: HookCanEmit in Hook must be a 256-bit (32-byte) hexadecimal value`,
|
||||
@@ -82,5 +79,10 @@ export function validateSetHook(tx: Record<string, unknown>): void {
|
||||
`SetHook: HookNamespace in Hook must be a 256-bit (32-byte) hexadecimal value`,
|
||||
)
|
||||
}
|
||||
if (HookName !== undefined && !HOOKNAME_REGEX.test(HookName)) {
|
||||
throw new ValidationError(
|
||||
`SetHook: HookName in Hook must be a hex string of 8-32 hex characters`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import { CheckCreate, validateCheckCreate } from './checkCreate'
|
||||
import { ClaimReward, validateClaimReward } from './claimReward'
|
||||
import { Clawback, validateClawback } from './clawback'
|
||||
import { BaseTransaction, isIssuedCurrency } from './common'
|
||||
import { Cron } from './cron'
|
||||
import { CronSet, validateCronSet } from './cronSet'
|
||||
import { DepositPreauth, validateDepositPreauth } from './depositPreauth'
|
||||
import { EnableAmendment } from './enableAmendment'
|
||||
import { EscrowCancel, validateEscrowCancel } from './escrowCancel'
|
||||
@@ -22,6 +24,8 @@ import { Invoke, validateInvoke } from './invoke'
|
||||
import { TransactionMetadata } from './metadata'
|
||||
import { OfferCancel, validateOfferCancel } from './offerCancel'
|
||||
import { OfferCreate, validateOfferCreate } from './offerCreate'
|
||||
import { OracleDelete, validateOracleDelete } from './oracleDelete'
|
||||
import { OracleSet, validateOracleSet } from './oracleSet'
|
||||
import { Payment, validatePayment } from './payment'
|
||||
import {
|
||||
PaymentChannelClaim,
|
||||
@@ -68,6 +72,7 @@ export type SubmittableTransaction =
|
||||
| CheckCreate
|
||||
| ClaimReward
|
||||
| Clawback
|
||||
| CronSet
|
||||
| DepositPreauth
|
||||
| EscrowCancel
|
||||
| EscrowCreate
|
||||
@@ -76,6 +81,8 @@ export type SubmittableTransaction =
|
||||
| Invoke
|
||||
| OfferCancel
|
||||
| OfferCreate
|
||||
| OracleDelete
|
||||
| OracleSet
|
||||
| Payment
|
||||
| PaymentChannelClaim
|
||||
| PaymentChannelCreate
|
||||
@@ -98,7 +105,7 @@ export type SubmittableTransaction =
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export type PseudoTransaction = EnableAmendment | SetFee | UNLModify
|
||||
export type PseudoTransaction = Cron | EnableAmendment | SetFee | UNLModify
|
||||
|
||||
/**
|
||||
* All transactions that can live on the XAHL
|
||||
@@ -210,6 +217,10 @@ export function validate(transaction: Record<string, unknown>): void {
|
||||
validateClawback(tx)
|
||||
break
|
||||
|
||||
case 'CronSet':
|
||||
validateCronSet(tx)
|
||||
break
|
||||
|
||||
case 'DepositPreauth':
|
||||
validateDepositPreauth(tx)
|
||||
break
|
||||
@@ -242,6 +253,14 @@ export function validate(transaction: Record<string, unknown>): void {
|
||||
validateOfferCreate(tx)
|
||||
break
|
||||
|
||||
case 'OracleDelete':
|
||||
validateOracleDelete(tx)
|
||||
break
|
||||
|
||||
case 'OracleSet':
|
||||
validateOracleSet(tx)
|
||||
break
|
||||
|
||||
case 'Payment':
|
||||
validatePayment(tx)
|
||||
break
|
||||
@@ -308,6 +327,7 @@ export function validate(transaction: Record<string, unknown>): void {
|
||||
|
||||
default:
|
||||
throw new ValidationError(
|
||||
// eslint-disable-next-line max-lines -- allowed here
|
||||
`Invalid field TransactionType: ${tx.TransactionType}`,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
/* eslint-disable no-param-reassign -- param reassign is safe */
|
||||
/* eslint-disable no-bitwise -- flags require bitwise operations */
|
||||
import { ValidationError } from '../../errors'
|
||||
import { Hook } from '../common/xahau'
|
||||
import { Hook, HookFlags, MintURITokenFlags } from '../common/xahau'
|
||||
import {
|
||||
AccountRootFlagsInterface,
|
||||
AccountRootFlags,
|
||||
} from '../ledger/AccountRoot'
|
||||
import { AccountSetTfFlags } from '../transactions/accountSet'
|
||||
import { ClaimRewardFlags } from '../transactions/claimReward'
|
||||
import { GlobalFlags } from '../transactions/common'
|
||||
import { CronSetFlags } from '../transactions/cronSet'
|
||||
import { OfferCreateFlags } from '../transactions/offerCreate'
|
||||
import { PaymentFlags } from '../transactions/payment'
|
||||
import { PaymentChannelClaimFlags } from '../transactions/paymentChannelClaim'
|
||||
import { SetHookFlagsInterface, SetHookFlags } from '../transactions/setHook'
|
||||
import {
|
||||
RemarkFlagsInterface,
|
||||
RemarkFlags,
|
||||
Remark,
|
||||
} from '../transactions/setRemarks'
|
||||
import { RemarkFlags, Remark } from '../transactions/setRemarks'
|
||||
import type { Transaction } from '../transactions/transaction'
|
||||
import { TrustSetFlags } from '../transactions/trustSet'
|
||||
import { URITokenMintFlags } from '../transactions/uriTokenMint'
|
||||
|
||||
import { isFlagEnabled } from '.'
|
||||
|
||||
@@ -52,6 +50,9 @@ const txToFlag = {
|
||||
PaymentChannelClaim: PaymentChannelClaimFlags,
|
||||
Payment: PaymentFlags,
|
||||
TrustSet: TrustSetFlags,
|
||||
URITokenMint: URITokenMintFlags,
|
||||
ClaimReward: ClaimRewardFlags,
|
||||
CronSet: CronSetFlags,
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,6 +61,36 @@ const txToFlag = {
|
||||
* @param tx - A transaction to set its flags to its numeric representation.
|
||||
*/
|
||||
export function setTransactionFlagsToNumber(tx: Transaction): void {
|
||||
if (tx.TransactionType === 'SetHook' && Array.isArray(tx.Hooks)) {
|
||||
tx.Hooks.forEach((hook: Hook) => {
|
||||
if (typeof hook.Hook.Flags === 'object') {
|
||||
hook.Hook.Flags = convertFlagsToNumber(hook.Hook.Flags, HookFlags)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (tx.TransactionType === 'Remit') {
|
||||
if (tx.MintURIToken != null && typeof tx.MintURIToken.Flags === 'object') {
|
||||
tx.MintURIToken.Flags = convertFlagsToNumber(
|
||||
tx.MintURIToken.Flags,
|
||||
MintURITokenFlags,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (tx.TransactionType === 'SetRemarks') {
|
||||
if (Array.isArray(tx.Remarks)) {
|
||||
tx.Remarks.forEach((remark: Remark) => {
|
||||
if (typeof remark.Remark.Flags === 'object') {
|
||||
remark.Remark.Flags = convertFlagsToNumber(
|
||||
remark.Remark.Flags,
|
||||
RemarkFlags,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (tx.Flags == null) {
|
||||
tx.Flags = 0
|
||||
return
|
||||
@@ -68,25 +99,6 @@ export function setTransactionFlagsToNumber(tx: Transaction): void {
|
||||
return
|
||||
}
|
||||
|
||||
if (tx.TransactionType === 'SetHook') {
|
||||
tx.Flags = convertFlagsToNumber(tx.Flags, SetHookFlags)
|
||||
tx.Hooks.forEach((hook: Hook) => {
|
||||
hook.Hook.Flags = convertFlagsToNumber(
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- idk
|
||||
hook.Hook.Flags as SetHookFlagsInterface,
|
||||
SetHookFlags,
|
||||
)
|
||||
})
|
||||
} else if (tx.TransactionType === 'SetRemarks') {
|
||||
tx.Remarks.forEach((remark: Remark) => {
|
||||
remark.Remark.Flags = convertFlagsToNumber(
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- idk
|
||||
remark.Remark.Flags as RemarkFlagsInterface,
|
||||
RemarkFlags,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
tx.Flags = txToFlag[tx.TransactionType]
|
||||
? convertFlagsToNumber(tx.Flags, txToFlag[tx.TransactionType])
|
||||
: 0
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { decode, encode } from 'xahau-binary-codec'
|
||||
|
||||
import type {
|
||||
Client,
|
||||
SubmitRequest,
|
||||
@@ -12,6 +10,7 @@ import { ValidationError, XahlError } from '../errors'
|
||||
import { Signer } from '../models/common'
|
||||
import { TxResponse } from '../models/methods'
|
||||
import { BaseTransaction } from '../models/transactions/common'
|
||||
import { decode, encode } from '../utils'
|
||||
|
||||
/** Approximate time for a ledger to close, in milliseconds */
|
||||
const LEDGER_CLOSE_TIME = 1000
|
||||
@@ -52,7 +51,7 @@ export async function submitRequest(
|
||||
failHard = false,
|
||||
): Promise<SubmitResponse> {
|
||||
if (!isSigned(signedTransaction)) {
|
||||
throw new ValidationError('Transaction must be signed')
|
||||
throw new ValidationError('Transaction must be signed.')
|
||||
}
|
||||
|
||||
const signedTxEncoded =
|
||||
|
||||
@@ -199,4 +199,28 @@ export function hashURIToken(issuer: string, uri: string): string {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the Hash of a Cron LedgerEntry.
|
||||
*
|
||||
* @param owner - Account of the Cron.
|
||||
* @param time - Time of the Cron.
|
||||
* @returns Hash of the Cron.
|
||||
* @category Utilities
|
||||
*/
|
||||
export function hashCron(owner: string, time: number): string {
|
||||
const timeString = bytesToHex([
|
||||
(time >> 24) & 0xff,
|
||||
(time >> 16) & 0xff,
|
||||
(time >> 8) & 0xff,
|
||||
(time >> 0) & 0xff,
|
||||
])
|
||||
|
||||
const nsHash = sha512Half(ledgerSpaceHex('cron')).slice(0, 16)
|
||||
const accHash = sha512Half(
|
||||
ledgerSpaceHex('cron') + timeString + addressToHex(owner),
|
||||
).slice(0, 40)
|
||||
|
||||
return nsHash + timeString + accHash
|
||||
}
|
||||
|
||||
export { hashLedgerHeader, hashSignedTx, hashLedger, hashStateTree, hashTxTree }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* XAH Ledger namespace prefixes.
|
||||
* Xahau Network namespace prefixes.
|
||||
*
|
||||
* The XAH Ledger is a key-value store. In order to avoid name collisions,
|
||||
* The Xahau Network is a key-value store. In order to avoid name collisions,
|
||||
* names are partitioned into namespaces.
|
||||
*
|
||||
* Each namespace is just a single character prefix.
|
||||
@@ -30,6 +30,7 @@ const ledgerSpaces = {
|
||||
check: 'C',
|
||||
depositPreauth: 'p',
|
||||
uriToken: 'U',
|
||||
cron: 'L',
|
||||
}
|
||||
|
||||
export default ledgerSpaces
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { EscrowFinish, Payment, Transaction } from '../../src'
|
||||
import { ValidationError } from '../../src/errors'
|
||||
import xahaud from '../fixtures/xahaud'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
import { assertRejects } from '../testUtils'
|
||||
|
||||
const NetworkID = 1025
|
||||
const Fee = '10'
|
||||
@@ -15,6 +17,8 @@ const LastLedgerSequence = 2908734
|
||||
|
||||
describe('client.autofill', function () {
|
||||
let testContext: XrplTestContext
|
||||
const AMOUNT = '1234'
|
||||
let paymentTx: Payment
|
||||
|
||||
async function setupMockRippledVersionAndID(
|
||||
buildVersion: string,
|
||||
@@ -38,6 +42,64 @@ describe('client.autofill', function () {
|
||||
})
|
||||
afterAll(async () => teardownClient(testContext))
|
||||
|
||||
beforeEach(async () => {
|
||||
paymentTx = {
|
||||
TransactionType: 'Payment',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
Amount: AMOUNT,
|
||||
Destination: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy',
|
||||
DestinationTag: 1,
|
||||
Fee: '12',
|
||||
Flags: 2147483648,
|
||||
LastLedgerSequence: 65953073,
|
||||
Sequence: 65923914,
|
||||
SigningPubKey:
|
||||
'02F9E33F16DF9507705EC954E3F94EB5F10D1FC4A354606DBE6297DBB1096FE654',
|
||||
TxnSignature:
|
||||
'3045022100E3FAE0EDEC3D6A8FF6D81BC9CF8288A61B7EEDE8071E90FF9314CB4621058D10022043545CF631706D700CEE65A1DB83EFDD185413808292D9D90F14D87D3DC2D8CB',
|
||||
InvoiceID:
|
||||
'6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B',
|
||||
Paths: [
|
||||
[{ currency: 'BTC', issuer: 'r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X' }],
|
||||
],
|
||||
SendMax: '100000000',
|
||||
}
|
||||
})
|
||||
|
||||
it('Validate Payment transaction API v2: Payment Transaction: Specify Only Amount field', async function () {
|
||||
const txResult = await testContext.client.autofill(paymentTx)
|
||||
|
||||
assert.strictEqual(txResult.Amount, AMOUNT)
|
||||
})
|
||||
|
||||
it('Validate Payment transaction API v2: Payment Transaction: Specify Only DeliverMax field', async function () {
|
||||
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||
paymentTx.DeliverMax = paymentTx.Amount
|
||||
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||
delete paymentTx.Amount
|
||||
const txResult = await testContext.client.autofill(paymentTx)
|
||||
|
||||
assert.strictEqual(txResult.Amount, AMOUNT)
|
||||
})
|
||||
|
||||
it('Validate Payment transaction API v2: Payment Transaction: identical DeliverMax and Amount fields', async function () {
|
||||
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||
paymentTx.DeliverMax = paymentTx.Amount
|
||||
|
||||
const txResult = await testContext.client.autofill(paymentTx)
|
||||
|
||||
assert.strictEqual(txResult.Amount, AMOUNT)
|
||||
assert.strictEqual('DeliverMax' in txResult, false)
|
||||
})
|
||||
|
||||
it('Validate Payment transaction API v2: Payment Transaction: differing DeliverMax and Amount fields', async function () {
|
||||
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||
paymentTx.DeliverMax = '6789'
|
||||
paymentTx.Amount = '1234'
|
||||
|
||||
await assertRejects(testContext.client.autofill(paymentTx), ValidationError)
|
||||
})
|
||||
|
||||
it('should not autofill if fields are present', async function () {
|
||||
const tx: Transaction = {
|
||||
TransactionType: 'DepositPreauth',
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import { stringToHex } from '@xrplf/isomorphic/utils'
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { OracleSet } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('get_aggregate_price', function () {
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const tx: OracleSet = {
|
||||
TransactionType: 'OracleSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
OracleDocumentID: 1234,
|
||||
LastUpdateTime: Math.floor(Date.now() / 1000),
|
||||
PriceDataSeries: [
|
||||
{
|
||||
PriceData: {
|
||||
BaseAsset: 'XRP',
|
||||
QuoteAsset: 'USD',
|
||||
AssetPrice: 740,
|
||||
Scale: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
Provider: stringToHex('chainlink'),
|
||||
URI: '6469645F6578616D706C65',
|
||||
AssetClass: stringToHex('currency'),
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||
|
||||
// confirm that the Oracle was actually created
|
||||
const getAggregatePriceResponse = await testContext.client.request({
|
||||
command: 'get_aggregate_price',
|
||||
account: testContext.wallet.classicAddress,
|
||||
base_asset: 'XRP',
|
||||
quote_asset: 'USD',
|
||||
trim: 20,
|
||||
oracles: [
|
||||
{
|
||||
account: testContext.wallet.classicAddress,
|
||||
oracle_document_id: 1234,
|
||||
},
|
||||
],
|
||||
})
|
||||
assert.deepEqual(getAggregatePriceResponse.result.entire_set, {
|
||||
mean: '0.74',
|
||||
size: 1,
|
||||
standard_deviation: '0',
|
||||
})
|
||||
assert.deepEqual(getAggregatePriceResponse.result.trimmed_set, {
|
||||
mean: '0.74',
|
||||
size: 1,
|
||||
standard_deviation: '0',
|
||||
})
|
||||
assert.equal(getAggregatePriceResponse.result.median, '0.74')
|
||||
assert.equal(getAggregatePriceResponse.result.time, tx.LastUpdateTime)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
@@ -117,6 +117,7 @@ describe('server_info (xahaud)', function () {
|
||||
'time',
|
||||
'uptime',
|
||||
'complete_ledgers',
|
||||
'complete_ledgers_pinned',
|
||||
'hostid',
|
||||
'load',
|
||||
'state_accounting',
|
||||
@@ -127,6 +128,7 @@ describe('server_info (xahaud)', function () {
|
||||
'node_size',
|
||||
'initial_sync_duration_us',
|
||||
'ports',
|
||||
'git',
|
||||
]
|
||||
assert.deepEqual(
|
||||
omit(response.result.info, removeKeys),
|
||||
|
||||
@@ -105,6 +105,7 @@ describe('server_state', function () {
|
||||
|
||||
const removeKeys = [
|
||||
'complete_ledgers',
|
||||
'complete_ledgers_pinned',
|
||||
'load',
|
||||
'state_accounting',
|
||||
'pubkey_node',
|
||||
@@ -117,6 +118,7 @@ describe('server_state', function () {
|
||||
'node_size',
|
||||
'initial_sync_duration_us',
|
||||
'ports',
|
||||
'git',
|
||||
]
|
||||
assert.deepEqual(
|
||||
omit(response.result.state, removeKeys),
|
||||
|
||||
85
packages/xahau/test/integration/requests/simulate.test.ts
Normal file
85
packages/xahau/test/integration/requests/simulate.test.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { AccountSet, SimulateRequest } from '../../../src'
|
||||
import { SimulateBinaryRequest } from '../../../src/models/methods/simulate'
|
||||
import serverUrl from '../serverUrl'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('simulate', function () {
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'json',
|
||||
async () => {
|
||||
const simulateRequest: SimulateRequest = {
|
||||
command: 'simulate',
|
||||
tx_json: {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.address,
|
||||
NFTokenMinter: testContext.wallet.address,
|
||||
},
|
||||
}
|
||||
const simulateResponse = await testContext.client.request(simulateRequest)
|
||||
|
||||
assert.equal(simulateResponse.type, 'response')
|
||||
assert.typeOf(simulateResponse.result.meta, 'object')
|
||||
assert.typeOf(simulateResponse.result.tx_json, 'object')
|
||||
assert.equal(simulateResponse.result.engine_result, 'tesSUCCESS')
|
||||
assert.isFalse(simulateResponse.result.applied)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'binary',
|
||||
async () => {
|
||||
const simulateRequest: SimulateBinaryRequest = {
|
||||
command: 'simulate',
|
||||
tx_json: {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.address,
|
||||
},
|
||||
binary: true,
|
||||
}
|
||||
const simulateResponse = await testContext.client.request(simulateRequest)
|
||||
|
||||
assert.equal(simulateResponse.type, 'response')
|
||||
assert.typeOf(simulateResponse.result.meta_blob, 'string')
|
||||
assert.typeOf(simulateResponse.result.tx_blob, 'string')
|
||||
assert.equal(simulateResponse.result.engine_result, 'tesSUCCESS')
|
||||
assert.isFalse(simulateResponse.result.applied)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'sugar',
|
||||
async () => {
|
||||
const tx: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.address,
|
||||
NFTokenMinter: testContext.wallet.address,
|
||||
}
|
||||
const simulateResponse = await testContext.client.simulate(tx)
|
||||
|
||||
assert.equal(simulateResponse.type, 'response')
|
||||
assert.typeOf(simulateResponse.result.meta, 'object')
|
||||
assert.typeOf(simulateResponse.result.tx_json, 'object')
|
||||
assert.equal(simulateResponse.result.engine_result, 'tesSUCCESS')
|
||||
assert.isFalse(simulateResponse.result.applied)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
@@ -1,24 +1,66 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { ClaimReward, ClaimRewardFlags } from '../../../src'
|
||||
import {
|
||||
ClaimReward,
|
||||
ClaimRewardFlags,
|
||||
SetHook,
|
||||
TrustSet,
|
||||
Wallet,
|
||||
} from '../../../src'
|
||||
import { RippleState } from '../../../src/models/ledger'
|
||||
import serverUrl from '../serverUrl'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { testTransaction } from '../utils'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ClaimReward', function () {
|
||||
let testContext: XrplIntegrationTestContext
|
||||
const acceptHook =
|
||||
'0061736D0100000001130360027F7F017F60037F7F7E017E60017F017E02170203656E76025F67000003656E760661636365707400010302010205030100020621057F01418088040B7F004180080B7F004180080B7F00418088040B7F004180080B07080104686F6F6B00020A9D80000199800000410141011080808080001A4100410042001081808080000B'
|
||||
|
||||
beforeEach(async () => {
|
||||
describe('XAH ClaimReward', function () {
|
||||
let testContext: XrplIntegrationTestContext
|
||||
let genesisWallet: Wallet
|
||||
|
||||
beforeAll(async () => {
|
||||
genesisWallet = new Wallet(
|
||||
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020',
|
||||
'001ACAAEDECE405B2A958212629E16F2EB46B153EEE94CDD350FDEFF52795525B7',
|
||||
)
|
||||
testContext = await setupClient(serverUrl)
|
||||
|
||||
const setHookTx: SetHook = {
|
||||
TransactionType: 'SetHook',
|
||||
Account: genesisWallet.classicAddress,
|
||||
Hooks: [
|
||||
{
|
||||
Hook: {
|
||||
CreateCode: acceptHook,
|
||||
HookApiVersion: 0,
|
||||
HookOn: '00'.repeat(32),
|
||||
HookNamespace: '00'.repeat(32),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
await testTransaction(testContext.client, setHookTx, genesisWallet)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
// reset Hook
|
||||
const setHookTx: SetHook = {
|
||||
TransactionType: 'SetHook',
|
||||
Account: genesisWallet.classicAddress,
|
||||
Hooks: [{ Hook: { CreateCode: '', Flags: { hsfOverride: true } } }],
|
||||
}
|
||||
await testTransaction(testContext.client, setHookTx, genesisWallet)
|
||||
|
||||
await teardownClient(testContext)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'opt in',
|
||||
@@ -26,7 +68,7 @@ describe('ClaimReward', function () {
|
||||
const tx: ClaimReward = {
|
||||
TransactionType: 'ClaimReward',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Issuer: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
Issuer: genesisWallet.address,
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||
@@ -42,6 +84,7 @@ describe('ClaimReward', function () {
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'opt out',
|
||||
async () => {
|
||||
@@ -67,3 +110,135 @@ describe('ClaimReward', function () {
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
describe('IOU ClaimReward', function () {
|
||||
let testContext: XrplIntegrationTestContext
|
||||
let issuerWallet: Wallet
|
||||
let hookWallet: Wallet
|
||||
|
||||
beforeAll(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
|
||||
issuerWallet = await generateFundedWallet(testContext.client)
|
||||
hookWallet = await generateFundedWallet(testContext.client)
|
||||
|
||||
const setHookTx: SetHook = {
|
||||
TransactionType: 'SetHook',
|
||||
Account: hookWallet.classicAddress,
|
||||
Hooks: [
|
||||
{
|
||||
Hook: {
|
||||
CreateCode: acceptHook,
|
||||
HookApiVersion: 0,
|
||||
HookOn: '00'.repeat(32),
|
||||
HookNamespace: '00'.repeat(32),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
await testTransaction(testContext.client, setHookTx, hookWallet)
|
||||
|
||||
const trustSetTx: TrustSet = {
|
||||
TransactionType: 'TrustSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
LimitAmount: {
|
||||
currency: 'USD',
|
||||
issuer: issuerWallet.address,
|
||||
value: '10000000',
|
||||
},
|
||||
}
|
||||
await testTransaction(testContext.client, trustSetTx, testContext.wallet)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
// reset Hook
|
||||
const setHookTx: SetHook = {
|
||||
TransactionType: 'SetHook',
|
||||
Account: hookWallet.classicAddress,
|
||||
Hooks: [{ Hook: { CreateCode: '', Flags: { hsfOverride: true } } }],
|
||||
}
|
||||
await testTransaction(testContext.client, setHookTx, hookWallet)
|
||||
|
||||
await teardownClient(testContext)
|
||||
})
|
||||
|
||||
it(
|
||||
'opt in',
|
||||
async () => {
|
||||
const tx: ClaimReward = {
|
||||
TransactionType: 'ClaimReward',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Issuer: hookWallet.classicAddress,
|
||||
ClaimCurrency: {
|
||||
currency: 'USD',
|
||||
issuer: issuerWallet.address,
|
||||
},
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||
|
||||
const rippleStateResponse = await testContext.client.request({
|
||||
command: 'ledger_entry',
|
||||
ripple_state: {
|
||||
currency: 'USD',
|
||||
accounts: [
|
||||
testContext.wallet.classicAddress,
|
||||
issuerWallet.classicAddress,
|
||||
],
|
||||
},
|
||||
})
|
||||
const node = rippleStateResponse.result.node as RippleState
|
||||
assert.exists(node)
|
||||
|
||||
// Either LowReward or HighReward must exist
|
||||
expect(Boolean(node.LowReward) || Boolean(node.HighReward))
|
||||
|
||||
if (node.LowReward) {
|
||||
assert.exists(node.LowReward.TrustLineRewardAccumulator)
|
||||
assert.exists(node.LowReward.RewardLgrFirst)
|
||||
assert.exists(node.LowReward.RewardLgrLast)
|
||||
assert.exists(node.LowReward.RewardTime)
|
||||
}
|
||||
if (node.HighReward) {
|
||||
assert.exists(node.HighReward.TrustLineRewardAccumulator)
|
||||
assert.exists(node.HighReward.RewardLgrFirst)
|
||||
assert.exists(node.HighReward.RewardLgrLast)
|
||||
assert.exists(node.HighReward.RewardTime)
|
||||
}
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'opt out',
|
||||
async () => {
|
||||
const tx: ClaimReward = {
|
||||
TransactionType: 'ClaimReward',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Flags: ClaimRewardFlags.tfOptOut,
|
||||
ClaimCurrency: {
|
||||
currency: 'USD',
|
||||
issuer: issuerWallet.address,
|
||||
},
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||
|
||||
const rippleStateResponse = await testContext.client.request({
|
||||
command: 'ledger_entry',
|
||||
ripple_state: {
|
||||
currency: 'USD',
|
||||
accounts: [
|
||||
testContext.wallet.classicAddress,
|
||||
issuerWallet.classicAddress,
|
||||
],
|
||||
},
|
||||
})
|
||||
const node = rippleStateResponse.result.node as RippleState
|
||||
assert.exists(node)
|
||||
assert.notExists(node.LowReward)
|
||||
assert.notExists(node.HighReward)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { stringToHex } from '@xrplf/isomorphic/utils'
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { OracleSet, OracleDelete } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('OracleDelete', function () {
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const setTx: OracleSet = {
|
||||
TransactionType: 'OracleSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
OracleDocumentID: 1234,
|
||||
LastUpdateTime: Math.floor(Date.now() / 1000),
|
||||
PriceDataSeries: [
|
||||
{
|
||||
PriceData: {
|
||||
BaseAsset: 'XRP',
|
||||
QuoteAsset: 'USD',
|
||||
AssetPrice: 740,
|
||||
Scale: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
Provider: stringToHex('chainlink'),
|
||||
URI: '6469645F6578616D706C65',
|
||||
AssetClass: stringToHex('currency'),
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, setTx, testContext.wallet)
|
||||
|
||||
const aoResult = await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testContext.wallet.classicAddress,
|
||||
type: 'oracle',
|
||||
})
|
||||
|
||||
// confirm that the Oracle was created
|
||||
assert.equal(aoResult.result.account_objects.length, 1)
|
||||
|
||||
const deleteTx: OracleDelete = {
|
||||
TransactionType: 'OracleDelete',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
OracleDocumentID: 1234,
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, deleteTx, testContext.wallet)
|
||||
|
||||
const aoResult2 = await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testContext.wallet.classicAddress,
|
||||
})
|
||||
|
||||
// confirm that the Oracle was actually deleted
|
||||
assert.equal(aoResult2.result.account_objects.length, 0)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
@@ -0,0 +1,91 @@
|
||||
import { stringToHex } from '@xrplf/isomorphic/utils'
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { OracleSet } from '../../../src'
|
||||
import { Oracle } from '../../../src/models/ledger'
|
||||
import serverUrl from '../serverUrl'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('OracleSet', function () {
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const tx: OracleSet = {
|
||||
TransactionType: 'OracleSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
OracleDocumentID: 1234,
|
||||
LastUpdateTime: Math.floor(Date.now() / 1000),
|
||||
PriceDataSeries: [
|
||||
{
|
||||
PriceData: {
|
||||
BaseAsset: 'XRP',
|
||||
QuoteAsset: 'USD',
|
||||
AssetPrice: 740,
|
||||
Scale: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
PriceData: {
|
||||
BaseAsset: 'XRP',
|
||||
QuoteAsset: 'INR',
|
||||
// Upper bound admissible value for AssetPrice field
|
||||
// large numeric values necessarily have to use str type in Javascript
|
||||
// number type uses double-precision floating point representation, hence represents a smaller range of values
|
||||
AssetPrice: 'ffffffffffffffff',
|
||||
Scale: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
Provider: stringToHex('chainlink'),
|
||||
URI: '6469645F6578616D706C65',
|
||||
AssetClass: stringToHex('currency'),
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||
|
||||
const result = await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testContext.wallet.classicAddress,
|
||||
type: 'oracle',
|
||||
})
|
||||
|
||||
// confirm that the Oracle was actually created
|
||||
assert.equal(result.result.account_objects.length, 1)
|
||||
|
||||
// confirm details of Oracle ledger entry object
|
||||
const oracle = result.result.account_objects[0] as Oracle
|
||||
assert.equal(oracle.LastUpdateTime, tx.LastUpdateTime)
|
||||
assert.equal(oracle.Owner, testContext.wallet.classicAddress)
|
||||
assert.equal(oracle.AssetClass, tx.AssetClass)
|
||||
assert.equal(oracle.Provider, tx.Provider)
|
||||
assert.equal(oracle.PriceDataSeries.length, 2)
|
||||
assert.equal(oracle.PriceDataSeries[1].PriceData.BaseAsset, 'XRP')
|
||||
assert.equal(oracle.PriceDataSeries[1].PriceData.QuoteAsset, 'USD')
|
||||
assert.equal(oracle.PriceDataSeries[1].PriceData.AssetPrice, '2e4')
|
||||
assert.equal(oracle.PriceDataSeries[1].PriceData.Scale, 3)
|
||||
assert.equal(oracle.Flags, 0)
|
||||
|
||||
// validate the serialization of large AssetPrice values
|
||||
assert.equal(
|
||||
oracle.PriceDataSeries[0].PriceData.AssetPrice,
|
||||
'ffffffffffffffff',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
@@ -1,3 +1,5 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { Payment, Wallet } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import {
|
||||
@@ -12,9 +14,22 @@ const TIMEOUT = 20000
|
||||
|
||||
describe('Payment', function () {
|
||||
let testContext: XrplIntegrationTestContext
|
||||
let paymentTx: Payment
|
||||
const AMOUNT = '10000000'
|
||||
// This wallet is used for DeliverMax related tests
|
||||
let senderWallet: Wallet
|
||||
|
||||
beforeEach(async () => {
|
||||
// this payment transaction JSON needs to be refreshed before every test.
|
||||
// Because, we tinker with Amount and DeliverMax fields in the API v2 tests
|
||||
paymentTx = {
|
||||
TransactionType: 'Payment',
|
||||
Account: senderWallet.classicAddress,
|
||||
Amount: AMOUNT,
|
||||
Destination: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy',
|
||||
}
|
||||
})
|
||||
|
||||
beforeAll(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
senderWallet = await generateFundedWallet(testContext.client)
|
||||
@@ -34,4 +49,57 @@ describe('Payment', function () {
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'Validate Payment transaction API v2: Payment Transaction: Specify Only Amount field',
|
||||
async () => {
|
||||
const result = await testTransaction(
|
||||
testContext.client,
|
||||
paymentTx,
|
||||
senderWallet,
|
||||
)
|
||||
|
||||
assert.equal(result.result.engine_result_code, 0)
|
||||
assert.equal((result.result.tx_json as Payment).Amount, AMOUNT)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'Validate Payment transaction API v2: Payment Transaction: Specify Only DeliverMax field',
|
||||
async () => {
|
||||
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||
paymentTx.DeliverMax = paymentTx.Amount
|
||||
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||
delete paymentTx.Amount
|
||||
|
||||
const result = await testTransaction(
|
||||
testContext.client,
|
||||
paymentTx,
|
||||
senderWallet,
|
||||
)
|
||||
|
||||
assert.equal(result.result.engine_result_code, 0)
|
||||
assert.equal((result.result.tx_json as Payment).Amount, AMOUNT)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'Validate Payment transaction API v2: Payment Transaction: identical DeliverMax and Amount fields',
|
||||
async () => {
|
||||
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||
paymentTx.DeliverMax = paymentTx.Amount
|
||||
|
||||
const result = await testTransaction(
|
||||
testContext.client,
|
||||
paymentTx,
|
||||
senderWallet,
|
||||
)
|
||||
|
||||
assert.equal(result.result.engine_result_code, 0)
|
||||
assert.equal((result.result.tx_json as Payment).Amount, AMOUNT)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { stringToHex } from '@xrplf/isomorphic/src/utils'
|
||||
import { stringToHex } from '@xrplf/isomorphic/utils'
|
||||
|
||||
import { Remit } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
@@ -65,6 +65,9 @@ describe('Remit', function () {
|
||||
Destination: wallet2.classicAddress,
|
||||
MintURIToken: {
|
||||
URI: stringToHex('https://example.com'),
|
||||
Flags: {
|
||||
tfBurnable: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
138
packages/xahau/test/integration/transactions/setHook.test.ts
Normal file
138
packages/xahau/test/integration/transactions/setHook.test.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import { SetHook, Wallet } from '../../../src'
|
||||
import { Hook, HookDefinition } from '../../../src/models/ledger'
|
||||
import serverUrl from '../serverUrl'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
const acceptHook =
|
||||
'0061736D0100000001130360027F7F017F60037F7F7E017E60017F017E02170203656E76025F67000003656E760661636365707400010302010205030100020621057F01418088040B7F004180080B7F004180080B7F00418088040B7F004180080B07080104686F6F6B00020A9D80000199800000410141011080808080001A4100410042001081808080000B'
|
||||
|
||||
describe('SetHook', function () {
|
||||
let testContext: XrplIntegrationTestContext
|
||||
let wallet: Wallet
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
wallet = await generateFundedWallet(testContext.client)
|
||||
})
|
||||
afterEach(async () => {
|
||||
// reset Hook
|
||||
const setHookTx: SetHook = {
|
||||
TransactionType: 'SetHook',
|
||||
Account: wallet.classicAddress,
|
||||
Hooks: [{ Hook: { CreateCode: '', Flags: { hsfOverride: true } } }],
|
||||
}
|
||||
await testTransaction(testContext.client, setHookTx, wallet)
|
||||
await teardownClient(testContext)
|
||||
})
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const setHookTx: SetHook = {
|
||||
TransactionType: 'SetHook',
|
||||
Account: wallet.classicAddress,
|
||||
Hooks: [
|
||||
{
|
||||
Hook: {
|
||||
CreateCode: acceptHook,
|
||||
HookApiVersion: 0,
|
||||
HookOn: '00'.repeat(32),
|
||||
HookCanEmit: '00'.repeat(32),
|
||||
HookName: '484F4F4B',
|
||||
HookParameters: [
|
||||
{
|
||||
HookParameter: {
|
||||
HookParameterName: 'DEADBEEF',
|
||||
HookParameterValue: 'DEADBEEF',
|
||||
},
|
||||
},
|
||||
],
|
||||
HookNamespace: '00'.repeat(32),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
await testTransaction(testContext.client, setHookTx, wallet)
|
||||
|
||||
const ledgerEntryResponse = await testContext.client.request({
|
||||
command: 'ledger_entry',
|
||||
hook: { account: wallet.classicAddress },
|
||||
})
|
||||
const node = ledgerEntryResponse.result.node as Hook
|
||||
expect(node.Hooks.length).toEqual(1)
|
||||
const hook = node.Hooks[0].Hook
|
||||
expect(Object.keys(hook).length).toEqual(2)
|
||||
expect(hook.HookHash).toBeDefined()
|
||||
expect(hook.HookName).toBeDefined()
|
||||
const hookHash = hook.HookHash!
|
||||
|
||||
const hookDefinitionResponse = await testContext.client.request({
|
||||
command: 'ledger_entry',
|
||||
hook_definition: hookHash,
|
||||
})
|
||||
const hookDefinitionNode = hookDefinitionResponse.result
|
||||
.node as HookDefinition
|
||||
expect(hookDefinitionNode.HookHash).toEqual(hookHash)
|
||||
expect(hookDefinitionNode.CreateCode).toEqual(acceptHook)
|
||||
expect(hookDefinitionNode.HookApiVersion).toEqual(0)
|
||||
expect(hookDefinitionNode.HookOn).toEqual('00'.repeat(32))
|
||||
expect(hookDefinitionNode.HookNamespace).toEqual('00'.repeat(32))
|
||||
// @ts-expect-error - HookName is not defined in HookDefinition
|
||||
expect(hookDefinitionNode.HookName).toBeUndefined()
|
||||
expect(hookDefinitionNode.HookParameters?.length).toEqual(1)
|
||||
const parameter = hookDefinitionNode.HookParameters![0].HookParameter
|
||||
expect(parameter.HookParameterName).toEqual('DEADBEEF')
|
||||
expect(parameter.HookParameterValue).toEqual('DEADBEEF')
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'hook on incoming/outgoing',
|
||||
async () => {
|
||||
const setHookTx: SetHook = {
|
||||
TransactionType: 'SetHook',
|
||||
Account: wallet.classicAddress,
|
||||
Hooks: [
|
||||
{
|
||||
Hook: {
|
||||
CreateCode: acceptHook,
|
||||
HookApiVersion: 0,
|
||||
HookOnIncoming: '00'.repeat(32),
|
||||
// eslint-disable-next-line no-inline-comments -- for readability
|
||||
HookOnOutgoing: `01${'00'.repeat(31)}`, // should be different from HookOnIncoming
|
||||
HookNamespace: '00'.repeat(32),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
await testTransaction(testContext.client, setHookTx, wallet)
|
||||
|
||||
const ledgerEntryResponse = await testContext.client.request({
|
||||
command: 'ledger_entry',
|
||||
hook: { account: wallet.classicAddress },
|
||||
})
|
||||
const node = ledgerEntryResponse.result.node as Hook
|
||||
const hook = node.Hooks[0].Hook
|
||||
const hookHash = hook.HookHash!
|
||||
|
||||
const hookDefinitionResponse = await testContext.client.request({
|
||||
command: 'ledger_entry',
|
||||
hook_definition: hookHash,
|
||||
})
|
||||
const hookDefinitionNode = hookDefinitionResponse.result
|
||||
.node as HookDefinition
|
||||
expect(hookDefinitionNode.HookOn).toBeUndefined()
|
||||
expect(hookDefinitionNode.HookOnIncoming).toBeDefined()
|
||||
expect(hookDefinitionNode.HookOnOutgoing).toBeDefined()
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
ECDSA,
|
||||
AccountLinesRequest,
|
||||
IssuedCurrency,
|
||||
XAHAUD_API_V2,
|
||||
TxResponse,
|
||||
} from '../../src'
|
||||
import {
|
||||
Payment,
|
||||
@@ -184,20 +186,22 @@ export async function verifySubmittedTransaction(
|
||||
hashTx?: string,
|
||||
): Promise<void> {
|
||||
const hash = hashTx ?? hashSignedTx(tx)
|
||||
const data = await client.request({
|
||||
const data: TxResponse = await client.request({
|
||||
command: 'tx',
|
||||
transaction: hash,
|
||||
// The current default version is v1, but we'll be using v2 for this test.
|
||||
api_version: XAHAUD_API_V2,
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: handle this API change for 2.0.0
|
||||
const decodedTx: any = typeof tx === 'string' ? decode(tx) : tx
|
||||
if (decodedTx.TransactionType === 'Payment' && client.apiVersion !== 1) {
|
||||
if (decodedTx.TransactionType === 'Payment') {
|
||||
decodedTx.DeliverMax = decodedTx.Amount
|
||||
delete decodedTx.Amount
|
||||
}
|
||||
|
||||
assert(data.result)
|
||||
assert.deepEqual(
|
||||
omit(data.result, [
|
||||
omit(data.result.tx_json, [
|
||||
'ctid',
|
||||
'date',
|
||||
'hash',
|
||||
|
||||
@@ -163,4 +163,43 @@ describe('AccountSet', function () {
|
||||
'AccountSet: invalid field NFTokenMinter',
|
||||
)
|
||||
})
|
||||
|
||||
it(`throws w/ invalid HookStateScale`, function () {
|
||||
account.HookStateScale = ''
|
||||
|
||||
assert.throws(
|
||||
() => validateAccountSet(account),
|
||||
ValidationError,
|
||||
'AccountSet: invalid field HookStateScale',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(account),
|
||||
ValidationError,
|
||||
'AccountSet: invalid field HookStateScale',
|
||||
)
|
||||
|
||||
account.HookStateScale = 17
|
||||
assert.throws(
|
||||
() => validateAccountSet(account),
|
||||
ValidationError,
|
||||
'AccountSet: HookStateScale must be less than or equal to 16',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(account),
|
||||
ValidationError,
|
||||
'AccountSet: HookStateScale must be less than or equal to 16',
|
||||
)
|
||||
|
||||
account.HookStateScale = 0
|
||||
assert.throws(
|
||||
() => validateAccountSet(account),
|
||||
ValidationError,
|
||||
'AccountSet: HookStateScale must be greater than or equal to 1',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(account),
|
||||
ValidationError,
|
||||
'AccountSet: HookStateScale must be greater than or equal to 1',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
121
packages/xahau/test/models/cronSet.test.ts
Normal file
121
packages/xahau/test/models/cronSet.test.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import {
|
||||
setTransactionFlagsToNumber,
|
||||
validate,
|
||||
ValidationError,
|
||||
} from '../../src'
|
||||
import {
|
||||
CronSetFlags,
|
||||
validateCronSet,
|
||||
} from '../../src/models/transactions/cronSet'
|
||||
|
||||
/**
|
||||
* CronSet Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('CronSet', function () {
|
||||
it(`verifies valid CronSet`, function () {
|
||||
let validCronSet = {
|
||||
TransactionType: 'CronSet',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
Fee: '100',
|
||||
RepeatCount: 256,
|
||||
DelaySeconds: 365 * 24 * 60 * 60,
|
||||
StartTime: 0,
|
||||
} as any
|
||||
|
||||
assert.doesNotThrow(() => validateCronSet(validCronSet))
|
||||
assert.doesNotThrow(() => validate(validCronSet))
|
||||
|
||||
validCronSet = {
|
||||
TransactionType: 'CronSet',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
Fee: '100',
|
||||
Flags: CronSetFlags.tfCronUnset,
|
||||
} as any
|
||||
|
||||
assert.doesNotThrow(() => validateCronSet(validCronSet))
|
||||
assert.doesNotThrow(() => validate(validCronSet))
|
||||
|
||||
validCronSet = {
|
||||
TransactionType: 'CronSet',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
Fee: '100',
|
||||
Flags: { tfCronUnset: true },
|
||||
} as any
|
||||
|
||||
assert.doesNotThrow(() => {
|
||||
setTransactionFlagsToNumber(validCronSet)
|
||||
validateCronSet(validCronSet)
|
||||
})
|
||||
assert.doesNotThrow(() => validate(validCronSet))
|
||||
})
|
||||
|
||||
it(`throws w/ invalid Delete Operation`, function () {
|
||||
const invalidDeleteOperation = {
|
||||
TransactionType: 'CronSet',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
Flags: CronSetFlags.tfCronUnset,
|
||||
RepeatCount: 1,
|
||||
DelaySeconds: 1,
|
||||
StartTime: 1,
|
||||
Fee: '100',
|
||||
} as any
|
||||
|
||||
assert.throws(
|
||||
() => validateCronSet(invalidDeleteOperation),
|
||||
ValidationError,
|
||||
'CronSet: RepeatCount, DelaySeconds, and StartTime must not be set when Flags is set to tfCronUnset',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(invalidDeleteOperation),
|
||||
ValidationError,
|
||||
'CronSet: RepeatCount, DelaySeconds, and StartTime must not be set when Flags is set to tfCronUnset',
|
||||
)
|
||||
})
|
||||
|
||||
it(`throws w/ invalid RepeatCount`, function () {
|
||||
const invalidRepeatCount = {
|
||||
TransactionType: 'CronSet',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
RepeatCount: 257,
|
||||
StartTime: 1,
|
||||
DelaySeconds: 1,
|
||||
Fee: '100',
|
||||
} as any
|
||||
|
||||
assert.throws(
|
||||
() => validateCronSet(invalidRepeatCount),
|
||||
ValidationError,
|
||||
'CronSet: RepeatCount must be less than 256',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(invalidRepeatCount),
|
||||
ValidationError,
|
||||
'CronSet: RepeatCount must be less than 256',
|
||||
)
|
||||
})
|
||||
it(`throws w/ invalid DelaySeconds`, function () {
|
||||
const invalidDelaySeconds = {
|
||||
TransactionType: 'CronSet',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
DelaySeconds: 365 * 24 * 60 * 60 + 1,
|
||||
StartTime: 1,
|
||||
RepeatCount: 1,
|
||||
Fee: '100',
|
||||
} as any
|
||||
|
||||
assert.throws(
|
||||
() => validateCronSet(invalidDelaySeconds),
|
||||
ValidationError,
|
||||
`CronSet: DelaySeconds must be less than ${365 * 24 * 60 * 60}`,
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(invalidDelaySeconds),
|
||||
ValidationError,
|
||||
`CronSet: DelaySeconds must be less than ${365 * 24 * 60 * 60}`,
|
||||
)
|
||||
})
|
||||
})
|
||||
40
packages/xahau/test/models/oracleDelete.test.ts
Normal file
40
packages/xahau/test/models/oracleDelete.test.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateOracleDelete } from '../../src/models/transactions/oracleDelete'
|
||||
|
||||
/**
|
||||
* OracleDelete Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('OracleDelete', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = {
|
||||
TransactionType: 'OracleDelete',
|
||||
Account: 'rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8',
|
||||
OracleDocumentID: 1234,
|
||||
} as any
|
||||
})
|
||||
|
||||
it('verifies valid OracleDelete', function () {
|
||||
assert.doesNotThrow(() => validateOracleDelete(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it(`throws w/ missing field OracleDocumentID`, function () {
|
||||
delete tx.OracleDocumentID
|
||||
const errorMessage = 'OracleDelete: missing field OracleDocumentID'
|
||||
assert.throws(() => validateOracleDelete(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ invalid OracleDocumentID`, function () {
|
||||
tx.OracleDocumentID = '1234'
|
||||
const errorMessage = 'OracleDelete: invalid field OracleDocumentID'
|
||||
assert.throws(() => validateOracleDelete(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
})
|
||||
212
packages/xahau/test/models/oracleSet.test.ts
Normal file
212
packages/xahau/test/models/oracleSet.test.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
import { stringToHex } from '@xrplf/isomorphic/dist/utils'
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateOracleSet } from '../../src/models/transactions/oracleSet'
|
||||
|
||||
/**
|
||||
* OracleSet Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('OracleSet', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = {
|
||||
TransactionType: 'OracleSet',
|
||||
Account: 'rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8',
|
||||
OracleDocumentID: 1234,
|
||||
LastUpdateTime: 768062172,
|
||||
PriceDataSeries: [
|
||||
{
|
||||
PriceData: {
|
||||
BaseAsset: 'XRP',
|
||||
QuoteAsset: 'USD',
|
||||
AssetPrice: 740,
|
||||
Scale: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
Provider: stringToHex('chainlink'),
|
||||
URI: '6469645F6578616D706C65',
|
||||
AssetClass: stringToHex('currency'),
|
||||
} as any
|
||||
})
|
||||
|
||||
it('verifies valid OracleSet', function () {
|
||||
assert.doesNotThrow(() => validateOracleSet(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it(`throws w/ missing field OracleDocumentID`, function () {
|
||||
delete tx.OracleDocumentID
|
||||
const errorMessage = 'OracleSet: missing field OracleDocumentID'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ invalid OracleDocumentID`, function () {
|
||||
tx.OracleDocumentID = '1234'
|
||||
const errorMessage = 'OracleSet: invalid field OracleDocumentID'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ missing field LastUpdateTime`, function () {
|
||||
delete tx.LastUpdateTime
|
||||
const errorMessage = 'OracleSet: missing field LastUpdateTime'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ invalid LastUpdateTime`, function () {
|
||||
tx.LastUpdateTime = '768062172'
|
||||
const errorMessage = 'OracleSet: invalid field LastUpdateTime'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ missing invalid Provider`, function () {
|
||||
tx.Provider = 1234
|
||||
const errorMessage = 'OracleSet: invalid field Provider'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ missing invalid URI`, function () {
|
||||
tx.URI = 1234
|
||||
const errorMessage = 'OracleSet: invalid field URI'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ missing invalid AssetClass`, function () {
|
||||
tx.AssetClass = 1234
|
||||
const errorMessage = 'OracleSet: invalid field AssetClass'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ invalid PriceDataSeries must be an array`, function () {
|
||||
tx.PriceDataSeries = 1234
|
||||
const errorMessage = 'OracleSet: PriceDataSeries must be an array'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ invalid PriceDataSeries must be an array of objects`, function () {
|
||||
tx.PriceDataSeries = [1234]
|
||||
const errorMessage =
|
||||
'OracleSet: PriceDataSeries must be an array of objects'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ PriceDataSeries must have at most 10 PriceData objects`, function () {
|
||||
tx.PriceDataSeries = new Array(11).fill({
|
||||
PriceData: {
|
||||
BaseAsset: 'XRP',
|
||||
QuoteAsset: 'USD',
|
||||
AssetPrice: 740,
|
||||
Scale: 3,
|
||||
},
|
||||
})
|
||||
const errorMessage =
|
||||
'OracleSet: PriceDataSeries must have at most 10 PriceData objects'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ PriceDataSeries must have a PriceData object`, function () {
|
||||
delete tx.PriceDataSeries[0].PriceData
|
||||
const errorMessage =
|
||||
'OracleSet: PriceDataSeries must have a `PriceData` object'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ PriceDataSeries must only have a single PriceData object`, function () {
|
||||
tx.PriceDataSeries[0].ExtraProp = 'extraprop'
|
||||
const errorMessage =
|
||||
'OracleSet: PriceDataSeries must only have a single PriceData object'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ missing BaseAsset of PriceDataSeries`, function () {
|
||||
delete tx.PriceDataSeries[0].PriceData.BaseAsset
|
||||
const errorMessage =
|
||||
'OracleSet: PriceDataSeries must have a `BaseAsset` string'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ missing QuoteAsset of PriceDataSeries`, function () {
|
||||
delete tx.PriceDataSeries[0].PriceData.QuoteAsset
|
||||
const errorMessage =
|
||||
'OracleSet: PriceDataSeries must have a `QuoteAsset` string'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ missing AssetPrice with Scale present of PriceDataSeries`, function () {
|
||||
delete tx.PriceDataSeries[0].PriceData.AssetPrice
|
||||
const errorMessage =
|
||||
'OracleSet: PriceDataSeries must have both `AssetPrice` and `Scale` if any are present'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ missing Scale with AssetPrice present of PriceDataSeries`, function () {
|
||||
delete tx.PriceDataSeries[0].PriceData.Scale
|
||||
const errorMessage =
|
||||
'OracleSet: PriceDataSeries must have both `AssetPrice` and `Scale` if any are present'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ invalid AssetPrice of PriceDataSeries`, function () {
|
||||
// value cannot be parsed as hexadecimal number
|
||||
tx.PriceDataSeries[0].PriceData.AssetPrice = 'ghij'
|
||||
const errorMessage =
|
||||
'OracleSet: Field AssetPrice must be a valid hex string'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`verifies valid AssetPrice of PriceDataSeries`, function () {
|
||||
// valid string which can be parsed as hexadecimal number
|
||||
tx.PriceDataSeries[0].PriceData.AssetPrice = 'ab15'
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it(`throws w/ invalid AssetPrice type in PriceDataSeries`, function () {
|
||||
tx.PriceDataSeries[0].PriceData.AssetPrice = ['sample', 'invalid', 'type']
|
||||
const errorMessage =
|
||||
'OracleSet: Field AssetPrice must be a string or a number'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ invalid Scale of PriceDataSeries`, function () {
|
||||
tx.PriceDataSeries[0].PriceData.Scale = '1234'
|
||||
const errorMessage = 'OracleSet: invalid field Scale'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ Scale must be in range 0-10 when above max`, function () {
|
||||
tx.PriceDataSeries[0].PriceData.Scale = 11
|
||||
const errorMessage = 'OracleSet: Scale must be in range 0-10'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ Scale must be in range 0-10 when below min`, function () {
|
||||
tx.PriceDataSeries[0].PriceData.Scale = -1
|
||||
const errorMessage = 'OracleSet: Scale must be in range 0-10'
|
||||
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
|
||||
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||
})
|
||||
})
|
||||
@@ -24,12 +24,15 @@ describe('SetHook', function () {
|
||||
'0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22',
|
||||
HookOn:
|
||||
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFF7',
|
||||
Flags: {
|
||||
hsfOverride: true,
|
||||
},
|
||||
HookCanEmit:
|
||||
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFF7',
|
||||
Flags: 1,
|
||||
HookApiVersion: 0,
|
||||
HookNamespace:
|
||||
'4FF9961269BF7630D32E15276569C94470174A5DA79FA567C0F62251AA9A36B9',
|
||||
HookName: 'DEADBEEF',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -64,6 +67,10 @@ describe('SetHook', function () {
|
||||
'0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22',
|
||||
HookOn:
|
||||
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFF7',
|
||||
HookOnIncoming:
|
||||
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFF7',
|
||||
HookOnOutgoing:
|
||||
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFF7',
|
||||
Flags: 1,
|
||||
HookApiVersion: 0,
|
||||
HookNamespace:
|
||||
@@ -91,30 +98,31 @@ describe('SetHook', function () {
|
||||
assert.throws(() => validate(setHookTx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it(`throws w/ invalid HookOn in Hooks`, function () {
|
||||
setHookTx.SignerQuorum = 2
|
||||
setHookTx.Hooks = [
|
||||
{
|
||||
Hook: {
|
||||
CreateCode:
|
||||
'0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22',
|
||||
HookOn: '',
|
||||
Flags: 1,
|
||||
HookApiVersion: 0,
|
||||
HookNamespace:
|
||||
'4FF9961269BF7630D32E15276569C94470174A5DA79FA567C0F62251AA9A36B9',
|
||||
it.each(['HookOn', 'HookOnIncoming', 'HookOnOutgoing'])(
|
||||
`throws w/ invalid %s in Hooks`,
|
||||
function (field: string) {
|
||||
setHookTx.Hooks = [
|
||||
{
|
||||
Hook: {
|
||||
CreateCode:
|
||||
'0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22',
|
||||
[field]: '',
|
||||
Flags: 1,
|
||||
HookApiVersion: 0,
|
||||
HookNamespace:
|
||||
'4FF9961269BF7630D32E15276569C94470174A5DA79FA567C0F62251AA9A36B9',
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
const errorMessage =
|
||||
'SetHook: HookOn in Hook must be a 256-bit (32-byte) hexadecimal value'
|
||||
assert.throws(
|
||||
() => validateSetHook(setHookTx),
|
||||
ValidationError,
|
||||
errorMessage,
|
||||
)
|
||||
assert.throws(() => validate(setHookTx), ValidationError, errorMessage)
|
||||
})
|
||||
]
|
||||
const errorMessage = `SetHook: ${field} in Hook must be a 256-bit (32-byte) hexadecimal value`
|
||||
assert.throws(
|
||||
() => validateSetHook(setHookTx),
|
||||
ValidationError,
|
||||
errorMessage,
|
||||
)
|
||||
assert.throws(() => validate(setHookTx), ValidationError, errorMessage)
|
||||
},
|
||||
)
|
||||
|
||||
it(`throws w/ invalid HookCanEmit in Hooks`, function () {
|
||||
setHookTx.Hooks = [
|
||||
@@ -166,4 +174,25 @@ describe('SetHook', function () {
|
||||
)
|
||||
assert.throws(() => validate(setHookTx), ValidationError, errorMessage)
|
||||
})
|
||||
|
||||
it.each(['', '0'.repeat(7), '0'.repeat(33), 'ZZZZZZZZ'])(
|
||||
`throws w/ invalid HookName in Hooks: %s`,
|
||||
function (value: string) {
|
||||
setHookTx.Hooks = [
|
||||
{
|
||||
Hook: {
|
||||
HookName: value,
|
||||
},
|
||||
},
|
||||
]
|
||||
const errorMessage =
|
||||
'SetHook: HookName in Hook must be a hex string of 8-32 hex characters'
|
||||
assert.throws(
|
||||
() => validateSetHook(setHookTx),
|
||||
ValidationError,
|
||||
errorMessage,
|
||||
)
|
||||
assert.throws(() => validate(setHookTx), ValidationError, errorMessage)
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
@@ -11,7 +11,17 @@ import {
|
||||
PaymentFlags,
|
||||
TrustSet,
|
||||
TrustSetFlags,
|
||||
Remit,
|
||||
convertStringToHex,
|
||||
SetHook,
|
||||
URITokenMint,
|
||||
URITokenMintFlags,
|
||||
ClaimReward,
|
||||
ClaimRewardFlags,
|
||||
CronSet,
|
||||
CronSetFlags,
|
||||
} from '../../src'
|
||||
import { HookFlags, MintURITokenFlags } from '../../src/models/common/xahau'
|
||||
import { AccountRootFlags } from '../../src/models/ledger'
|
||||
import { isFlagEnabled } from '../../src/models/utils'
|
||||
import {
|
||||
@@ -141,6 +151,94 @@ describe('Models Utils', function () {
|
||||
assert.strictEqual(tx.Flags, expected)
|
||||
})
|
||||
|
||||
it('sets URITokenMintFlags to its numeric value', function () {
|
||||
const tx: URITokenMint = {
|
||||
TransactionType: 'URITokenMint',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
URI: convertStringToHex('https://xahau.network'),
|
||||
Flags: {
|
||||
tfBurnable: true,
|
||||
},
|
||||
}
|
||||
const { tfBurnable } = URITokenMintFlags
|
||||
const expected: number = tfBurnable
|
||||
|
||||
setTransactionFlagsToNumber(tx)
|
||||
assert.strictEqual(tx.Flags, expected)
|
||||
})
|
||||
|
||||
it('sets ClaimRewardFlags to its numeric value', function () {
|
||||
const tx: ClaimReward = {
|
||||
TransactionType: 'ClaimReward',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
Flags: {
|
||||
tfOptOut: true,
|
||||
},
|
||||
}
|
||||
const { tfOptOut } = ClaimRewardFlags
|
||||
const expected: number = tfOptOut
|
||||
|
||||
setTransactionFlagsToNumber(tx)
|
||||
assert.strictEqual(tx.Flags, expected)
|
||||
})
|
||||
|
||||
it('sets CronSetFlags to its numeric value', function () {
|
||||
const tx: CronSet = {
|
||||
TransactionType: 'CronSet',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
Flags: {
|
||||
tfCronUnset: true,
|
||||
},
|
||||
}
|
||||
const { tfCronUnset } = CronSetFlags
|
||||
const expected: number = tfCronUnset
|
||||
|
||||
setTransactionFlagsToNumber(tx)
|
||||
assert.strictEqual(tx.Flags, expected)
|
||||
})
|
||||
|
||||
it('sets MintURITokenFlags in Remit Transaction to its numeric value', function () {
|
||||
const tx: Remit = {
|
||||
TransactionType: 'Remit',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
Destination: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX',
|
||||
MintURIToken: {
|
||||
URI: convertStringToHex('https://xahau.network'),
|
||||
Flags: {
|
||||
tfBurnable: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
setTransactionFlagsToNumber(tx)
|
||||
const expected = MintURITokenFlags.tfBurnable
|
||||
assert.strictEqual(tx.MintURIToken?.Flags, expected)
|
||||
})
|
||||
|
||||
it('sets HookFlags in SetHook Transaction to its numeric value', function () {
|
||||
const tx: SetHook = {
|
||||
TransactionType: 'SetHook',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
Hooks: [
|
||||
{
|
||||
Hook: {
|
||||
// invalid flags but for testing purposes
|
||||
Flags: {
|
||||
hsfCollect: true,
|
||||
hsfNSDelete: true,
|
||||
hsfOverride: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
setTransactionFlagsToNumber(tx)
|
||||
const expected =
|
||||
HookFlags.hsfCollect | HookFlags.hsfNSDelete | HookFlags.hsfOverride
|
||||
assert.strictEqual(tx.Hooks[0].Hook.Flags, expected)
|
||||
})
|
||||
|
||||
it('sets other transaction types flags to its numeric value', function () {
|
||||
const tx: DepositPreauth = {
|
||||
TransactionType: 'DepositPreauth',
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
hashAccountRoot,
|
||||
hashOfferId,
|
||||
hashSignerListId,
|
||||
hashCron,
|
||||
} from '../../src/utils/hashes'
|
||||
import fixtures from '../fixtures/xahaud'
|
||||
import { assertResultMatch } from '../testUtils'
|
||||
@@ -148,6 +149,15 @@ describe('Hashes', function () {
|
||||
assert.equal(actualEntryHash, expectedEntryHash)
|
||||
})
|
||||
|
||||
it('calcCronEntryHash', function () {
|
||||
const owner = 'rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn'
|
||||
const time = 30758410
|
||||
const expectedEntryHash =
|
||||
'F7B645436187CC6101D5560AF1127C15262825333ADC45B3155918D98149BD3F'
|
||||
const actualEntryHash = hashCron(owner, time)
|
||||
assert.equal(actualEntryHash, expectedEntryHash)
|
||||
})
|
||||
|
||||
it('Hash a signed transaction correctly', function () {
|
||||
const expected_hash =
|
||||
'458101D51051230B1D56E9ACAFAA34451BF65FA000F95DF6F0FF5B3A62D83FC2'
|
||||
|
||||
@@ -48,7 +48,7 @@ module.exports = {
|
||||
const localConfig = merge(config, {
|
||||
mode: "production",
|
||||
output: {
|
||||
filename: `${filename}-latest.min.js`,
|
||||
filename: `${filename}-latest-min.js`,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user