mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-12-06 17:27:59 +00:00
Compare commits
13 Commits
v4.1.0
...
ripple-bin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b16d0cfe3 | ||
|
|
35e40d9d71 | ||
|
|
ea9e3dcc98 | ||
|
|
61da4c567a | ||
|
|
189abc1a26 | ||
|
|
ce5ca316ca | ||
|
|
991a1d29a4 | ||
|
|
23d26c8c2e | ||
|
|
abdb192c69 | ||
|
|
84943ae0b6 | ||
|
|
d8126807a4 | ||
|
|
7a2fa3fcaa | ||
|
|
76c3355858 |
@@ -63,17 +63,10 @@ online_delete=256
|
|||||||
[debug_logfile]
|
[debug_logfile]
|
||||||
/var/log/rippled/debug.log
|
/var/log/rippled/debug.log
|
||||||
|
|
||||||
[sntp_servers]
|
|
||||||
time.windows.com
|
|
||||||
time.apple.com
|
|
||||||
time.nist.gov
|
|
||||||
pool.ntp.org
|
|
||||||
|
|
||||||
[ips]
|
[ips]
|
||||||
r.ripple.com 51235
|
r.ripple.com 51235
|
||||||
|
|
||||||
[validators_file]
|
|
||||||
validators.txt
|
|
||||||
|
|
||||||
[rpc_startup]
|
[rpc_startup]
|
||||||
{ "command": "log_level", "severity": "info" }
|
{ "command": "log_level", "severity": "info" }
|
||||||
@@ -180,6 +173,7 @@ fixXChainRewardRounding
|
|||||||
fixPreviousTxnID
|
fixPreviousTxnID
|
||||||
fixAMMv1_1
|
fixAMMv1_1
|
||||||
# 2.3.0 Amendments
|
# 2.3.0 Amendments
|
||||||
|
AMMClawback
|
||||||
fixAMMv1_2
|
fixAMMv1_2
|
||||||
Credentials
|
Credentials
|
||||||
NFTokenMintOffer
|
NFTokenMintOffer
|
||||||
@@ -188,3 +182,6 @@ fixNFTokenPageLinks
|
|||||||
fixInnerObjTemplate2
|
fixInnerObjTemplate2
|
||||||
fixEnforceNFTokenTrustline
|
fixEnforceNFTokenTrustline
|
||||||
fixReducedOffersV2
|
fixReducedOffersV2
|
||||||
|
DeepFreeze
|
||||||
|
DynamicNFT
|
||||||
|
PermissionedDomains
|
||||||
|
|||||||
2
.github/workflows/nodejs.yml
vendored
2
.github/workflows/nodejs.yml
vendored
@@ -4,7 +4,7 @@
|
|||||||
name: Node.js CI
|
name: Node.js CI
|
||||||
|
|
||||||
env:
|
env:
|
||||||
RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.3.0-rc1
|
RIPPLED_DOCKER_IMAGE: rippleci/rippled:develop
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ From the top-level xrpl.js folder (one level above `packages`), run the followin
|
|||||||
```bash
|
```bash
|
||||||
npm install
|
npm install
|
||||||
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
|
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
|
||||||
docker run -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:2.3.0-rc1 -c 'rippled -a'
|
docker run -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:develop -c 'rippled -a'
|
||||||
npm run build
|
npm run build
|
||||||
npm run test:integration
|
npm run test:integration
|
||||||
```
|
```
|
||||||
@@ -76,7 +76,7 @@ Breaking down the command:
|
|||||||
`--name rippled_standalone` is an instance name for clarity
|
`--name rippled_standalone` is an instance name for clarity
|
||||||
* `--volume $PWD/.ci-config:/etc/opt/ripple/` identifies the `rippled.cfg` and `validators.txt` to import. It must be an absolute path, so we use `$PWD` instead of `./`.
|
* `--volume $PWD/.ci-config:/etc/opt/ripple/` identifies the `rippled.cfg` and `validators.txt` to import. It must be an absolute path, so we use `$PWD` instead of `./`.
|
||||||
* `rippleci/rippled` is an image that is regularly updated with the latest `rippled` releases
|
* `rippleci/rippled` is an image that is regularly updated with the latest `rippled` releases
|
||||||
* `--entrypoint bash rippleci/rippled:2.3.0-rc1` manually overrides the entrypoint (for versions of rippled >= 2.3.0)
|
* `--entrypoint bash rippleci/rippled:develop` manually overrides the entrypoint (for the latest version of rippled on the `develop` branch)
|
||||||
* `-c 'rippled -a'` provides the bash command to start `rippled` in standalone mode from the manual entrypoint
|
* `-c 'rippled -a'` provides the bash command to start `rippled` in standalone mode from the manual entrypoint
|
||||||
|
|
||||||
### Browser Tests
|
### Browser Tests
|
||||||
@@ -92,7 +92,7 @@ This should be run from the `xrpl.js` top level folder (one above the `packages`
|
|||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
|
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
|
||||||
docker run -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:2.3.0-rc1 -c 'rippled -a'
|
docker run -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:develop -c 'rippled -a'
|
||||||
npm run test:browser
|
npm run test:browser
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
817
package-lock.json
generated
817
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -58,7 +58,7 @@
|
|||||||
"typescript": "^5.1.6",
|
"typescript": "^5.1.6",
|
||||||
"webpack": "^5.81.0",
|
"webpack": "^5.81.0",
|
||||||
"webpack-bundle-analyzer": "^4.1.0",
|
"webpack-bundle-analyzer": "^4.1.0",
|
||||||
"webpack-cli": "^5.0.1"
|
"webpack-cli": "^6.0.1"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"./packages/*"
|
"./packages/*"
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## 2.3.0 (2025-2-13)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Support for the AMMClawback amendment (XLS-73)
|
||||||
|
* Support for the Permissioned Domains amendment (XLS-80).
|
||||||
|
|
||||||
## 2.2.0 (2024-12-23)
|
## 2.2.0 (2024-12-23)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -11,6 +17,7 @@
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
* Support for the Price Oracles amendment (XLS-47).
|
* Support for the Price Oracles amendment (XLS-47).
|
||||||
|
* Support for the `DynamicNFT` amendment (XLS-46)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* Better error handling/error messages for serialization/deserialization errors.
|
* Better error handling/error messages for serialization/deserialization errors.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ripple-binary-codec",
|
"name": "ripple-binary-codec",
|
||||||
"version": "2.2.0",
|
"version": "2.3.0",
|
||||||
"description": "XRP Ledger binary codec",
|
"description": "XRP Ledger binary codec",
|
||||||
"files": [
|
"files": [
|
||||||
"dist/*",
|
"dist/*",
|
||||||
|
|||||||
@@ -1250,6 +1250,16 @@
|
|||||||
"type": "Hash256"
|
"type": "Hash256"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"DomainID",
|
||||||
|
{
|
||||||
|
"nth": 34,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Hash256"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"hash",
|
"hash",
|
||||||
{
|
{
|
||||||
@@ -2530,6 +2540,15 @@
|
|||||||
"type": "STArray"
|
"type": "STArray"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"AcceptedCredentials", {
|
||||||
|
"nth": 28,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "STArray"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"CloseResolution",
|
"CloseResolution",
|
||||||
{
|
{
|
||||||
@@ -2863,6 +2882,7 @@
|
|||||||
"Oracle": 128,
|
"Oracle": 128,
|
||||||
"Credential": 129,
|
"Credential": 129,
|
||||||
"PayChannel": 120,
|
"PayChannel": 120,
|
||||||
|
"PermissionedDomain": 130,
|
||||||
"RippleState": 114,
|
"RippleState": 114,
|
||||||
"SignerList": 83,
|
"SignerList": 83,
|
||||||
"Ticket": 84,
|
"Ticket": 84,
|
||||||
@@ -3053,6 +3073,7 @@
|
|||||||
},
|
},
|
||||||
"TRANSACTION_TYPES": {
|
"TRANSACTION_TYPES": {
|
||||||
"AMMBid": 39,
|
"AMMBid": 39,
|
||||||
|
"AMMClawback": 31,
|
||||||
"AMMCreate": 35,
|
"AMMCreate": 35,
|
||||||
"AMMDelete": 40,
|
"AMMDelete": 40,
|
||||||
"AMMDeposit": 36,
|
"AMMDeposit": 36,
|
||||||
@@ -3085,6 +3106,7 @@
|
|||||||
"NFTokenCancelOffer": 28,
|
"NFTokenCancelOffer": 28,
|
||||||
"NFTokenCreateOffer": 27,
|
"NFTokenCreateOffer": 27,
|
||||||
"NFTokenMint": 25,
|
"NFTokenMint": 25,
|
||||||
|
"NFTokenModify": 61,
|
||||||
"OfferCancel": 8,
|
"OfferCancel": 8,
|
||||||
"OfferCreate": 7,
|
"OfferCreate": 7,
|
||||||
"OracleDelete": 52,
|
"OracleDelete": 52,
|
||||||
@@ -3093,6 +3115,8 @@
|
|||||||
"PaymentChannelClaim": 15,
|
"PaymentChannelClaim": 15,
|
||||||
"PaymentChannelCreate": 13,
|
"PaymentChannelCreate": 13,
|
||||||
"PaymentChannelFund": 14,
|
"PaymentChannelFund": 14,
|
||||||
|
"PermissionedDomainSet": 62,
|
||||||
|
"PermissionedDomainDelete": 63,
|
||||||
"SetFee": 101,
|
"SetFee": 101,
|
||||||
"SetRegularKey": 5,
|
"SetRegularKey": 5,
|
||||||
"SignerListSet": 12,
|
"SignerListSet": 12,
|
||||||
|
|||||||
@@ -2,7 +2,22 @@
|
|||||||
|
|
||||||
Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xrpl-announce) for release announcements. We recommend that xrpl.js (ripple-lib) users stay up-to-date with the latest stable release.
|
Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xrpl-announce) for release announcements. We recommend that xrpl.js (ripple-lib) users stay up-to-date with the latest stable release.
|
||||||
|
|
||||||
## Unreleased Changes
|
## Unreleased
|
||||||
|
|
||||||
|
## 4.2.0 (2025-2-13)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Support for the AMMClawback amendment (XLS-73)
|
||||||
|
* Adds utility function `convertTxFlagsToNumber`
|
||||||
|
* Support for the Permissioned Domains amendment (XLS-80).
|
||||||
|
* Support for the `simulate` RPC ([XLS-69](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069-simulate))
|
||||||
|
* Support for XLS-77d Deep-Freeze amendment
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Deprecated `setTransactionFlagsToNumber`. Start using convertTxFlagsToNumber instead
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Include `network_id` field in the `server_state` response interface.
|
||||||
|
|
||||||
## 4.1.0 (2024-12-23)
|
## 4.1.0 (2024-12-23)
|
||||||
|
|
||||||
@@ -11,6 +26,7 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
|
|||||||
* New `MPTAmount` type support for `Payment` and `Clawback` transactions
|
* New `MPTAmount` type support for `Payment` and `Clawback` transactions
|
||||||
* `parseTransactionFlags` as a utility function in the xrpl package to streamline transactions flags-to-map conversion
|
* `parseTransactionFlags` as a utility function in the xrpl package to streamline transactions flags-to-map conversion
|
||||||
* Support for XLS-70d (Credentials)
|
* Support for XLS-70d (Credentials)
|
||||||
|
* Support for the `DynamicNFT` amendment (XLS-46)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* `TransactionStream` model supports APIv2
|
* `TransactionStream` model supports APIv2
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "xrpl",
|
"name": "xrpl",
|
||||||
"version": "4.1.0",
|
"version": "4.2.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser",
|
"description": "A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
"bignumber.js": "^9.0.0",
|
"bignumber.js": "^9.0.0",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
"ripple-address-codec": "^5.0.0",
|
"ripple-address-codec": "^5.0.0",
|
||||||
"ripple-binary-codec": "^2.2.0",
|
"ripple-binary-codec": "^2.3.0",
|
||||||
"ripple-keypairs": "^2.0.0"
|
"ripple-keypairs": "^2.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"run-s": "^0.0.0",
|
"run-s": "^0.0.0",
|
||||||
"typedoc": "0.26.11",
|
"typedoc": "0.27.6",
|
||||||
"ws": "^8.14.2"
|
"ws": "^8.14.2"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
|||||||
@@ -40,14 +40,19 @@ import type {
|
|||||||
MarkerRequest,
|
MarkerRequest,
|
||||||
MarkerResponse,
|
MarkerResponse,
|
||||||
SubmitResponse,
|
SubmitResponse,
|
||||||
|
SimulateRequest,
|
||||||
} from '../models/methods'
|
} from '../models/methods'
|
||||||
import type { BookOffer, BookOfferCurrency } from '../models/methods/bookOffers'
|
import type { BookOffer, BookOfferCurrency } from '../models/methods/bookOffers'
|
||||||
|
import {
|
||||||
|
SimulateBinaryResponse,
|
||||||
|
SimulateJsonResponse,
|
||||||
|
} from '../models/methods/simulate'
|
||||||
import type {
|
import type {
|
||||||
EventTypes,
|
EventTypes,
|
||||||
OnEventToListenerMap,
|
OnEventToListenerMap,
|
||||||
} from '../models/methods/subscribe'
|
} from '../models/methods/subscribe'
|
||||||
import type { SubmittableTransaction } from '../models/transactions'
|
import type { SubmittableTransaction } from '../models/transactions'
|
||||||
import { setTransactionFlagsToNumber } from '../models/utils/flags'
|
import { convertTxFlagsToNumber } from '../models/utils/flags'
|
||||||
import {
|
import {
|
||||||
ensureClassicAddress,
|
ensureClassicAddress,
|
||||||
submitRequest,
|
submitRequest,
|
||||||
@@ -665,7 +670,7 @@ class Client extends EventEmitter<EventTypes> {
|
|||||||
const tx = { ...transaction }
|
const tx = { ...transaction }
|
||||||
|
|
||||||
setValidAddresses(tx)
|
setValidAddresses(tx)
|
||||||
setTransactionFlagsToNumber(tx)
|
tx.Flags = convertTxFlagsToNumber(tx)
|
||||||
|
|
||||||
const promises: Array<Promise<void>> = []
|
const promises: Array<Promise<void>> = []
|
||||||
if (tx.NetworkID == null) {
|
if (tx.NetworkID == null) {
|
||||||
@@ -764,6 +769,41 @@ class Client extends EventEmitter<EventTypes> {
|
|||||||
return submitRequest(this, signedTx, opts?.failHard)
|
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
|
* 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).
|
* validated ledger (or has errored/will not be included for some reason).
|
||||||
|
|||||||
@@ -8,8 +8,9 @@
|
|||||||
*/
|
*/
|
||||||
export * as LedgerEntry from './ledger'
|
export * as LedgerEntry from './ledger'
|
||||||
export {
|
export {
|
||||||
setTransactionFlagsToNumber,
|
|
||||||
parseAccountRootFlags,
|
parseAccountRootFlags,
|
||||||
|
setTransactionFlagsToNumber,
|
||||||
|
convertTxFlagsToNumber,
|
||||||
parseTransactionFlags,
|
parseTransactionFlags,
|
||||||
} from './utils/flags'
|
} from './utils/flags'
|
||||||
export * from './methods'
|
export * from './methods'
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import NegativeUNL from './NegativeUNL'
|
|||||||
import Offer from './Offer'
|
import Offer from './Offer'
|
||||||
import Oracle from './Oracle'
|
import Oracle from './Oracle'
|
||||||
import PayChannel from './PayChannel'
|
import PayChannel from './PayChannel'
|
||||||
|
import PermissionedDomain from './PermissionedDomain'
|
||||||
import RippleState from './RippleState'
|
import RippleState from './RippleState'
|
||||||
import SignerList from './SignerList'
|
import SignerList from './SignerList'
|
||||||
import Ticket from './Ticket'
|
import Ticket from './Ticket'
|
||||||
@@ -35,6 +36,7 @@ type LedgerEntry =
|
|||||||
| Offer
|
| Offer
|
||||||
| Oracle
|
| Oracle
|
||||||
| PayChannel
|
| PayChannel
|
||||||
|
| PermissionedDomain
|
||||||
| RippleState
|
| RippleState
|
||||||
| SignerList
|
| SignerList
|
||||||
| Ticket
|
| Ticket
|
||||||
@@ -61,6 +63,7 @@ type LedgerEntryFilter =
|
|||||||
| 'offer'
|
| 'offer'
|
||||||
| 'oracle'
|
| 'oracle'
|
||||||
| 'payment_channel'
|
| 'payment_channel'
|
||||||
|
| 'permissioned_domain'
|
||||||
| 'signer_list'
|
| 'signer_list'
|
||||||
| 'state'
|
| 'state'
|
||||||
| 'ticket'
|
| 'ticket'
|
||||||
|
|||||||
29
packages/xrpl/src/models/ledger/PermissionedDomain.ts
Normal file
29
packages/xrpl/src/models/ledger/PermissionedDomain.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { AuthorizeCredential } from '../common'
|
||||||
|
|
||||||
|
import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'
|
||||||
|
|
||||||
|
export default interface PermissionedDomain
|
||||||
|
extends BaseLedgerEntry,
|
||||||
|
HasPreviousTxnID {
|
||||||
|
/* The ledger object's type (PermissionedDomain). */
|
||||||
|
LedgerEntryType: 'PermissionedDomain'
|
||||||
|
|
||||||
|
/* The account that controls the settings of the domain. */
|
||||||
|
Owner: string
|
||||||
|
|
||||||
|
/* The credentials that are accepted by the domain.
|
||||||
|
Ownership of one of these credentials automatically
|
||||||
|
makes you a member of the domain. */
|
||||||
|
AcceptedCredentials: AuthorizeCredential[]
|
||||||
|
|
||||||
|
/* Flag values associated with this object. */
|
||||||
|
Flags: 0
|
||||||
|
|
||||||
|
/* Owner account's directory page containing the PermissionedDomain object. */
|
||||||
|
OwnerNode: string
|
||||||
|
|
||||||
|
/* The Sequence value of the PermissionedDomainSet
|
||||||
|
transaction that created this domain. Used in combination
|
||||||
|
with the Account to identify this domain. */
|
||||||
|
Sequence: number
|
||||||
|
}
|
||||||
@@ -77,4 +77,8 @@ export enum RippleStateFlags {
|
|||||||
lsfHighFreeze = 0x00800000,
|
lsfHighFreeze = 0x00800000,
|
||||||
// True, trust line to AMM. Used by client apps to identify payments via AMM.
|
// True, trust line to AMM. Used by client apps to identify payments via AMM.
|
||||||
lsfAMMNode = 0x01000000,
|
lsfAMMNode = 0x01000000,
|
||||||
|
// True, low side has set deep freeze flag
|
||||||
|
lsfLowDeepFreeze = 0x02000000,
|
||||||
|
// True, high side has set deep freeze flag
|
||||||
|
lsfHighDeepFreeze = 0x04000000,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,6 +148,14 @@ import {
|
|||||||
StateAccountingFinal,
|
StateAccountingFinal,
|
||||||
} from './serverInfo'
|
} from './serverInfo'
|
||||||
import { ServerStateRequest, ServerStateResponse } from './serverState'
|
import { ServerStateRequest, ServerStateResponse } from './serverState'
|
||||||
|
import {
|
||||||
|
SimulateBinaryRequest,
|
||||||
|
SimulateBinaryResponse,
|
||||||
|
SimulateJsonRequest,
|
||||||
|
SimulateJsonResponse,
|
||||||
|
SimulateRequest,
|
||||||
|
SimulateResponse,
|
||||||
|
} from './simulate'
|
||||||
import { SubmitRequest, SubmitResponse } from './submit'
|
import { SubmitRequest, SubmitResponse } from './submit'
|
||||||
import {
|
import {
|
||||||
SubmitMultisignedRequest,
|
SubmitMultisignedRequest,
|
||||||
@@ -203,6 +211,7 @@ type Request =
|
|||||||
| LedgerDataRequest
|
| LedgerDataRequest
|
||||||
| LedgerEntryRequest
|
| LedgerEntryRequest
|
||||||
// transaction methods
|
// transaction methods
|
||||||
|
| SimulateRequest
|
||||||
| SubmitRequest
|
| SubmitRequest
|
||||||
| SubmitMultisignedRequest
|
| SubmitMultisignedRequest
|
||||||
| TransactionEntryRequest
|
| TransactionEntryRequest
|
||||||
@@ -261,6 +270,7 @@ type Response<Version extends APIVersion = typeof DEFAULT_API_VERSION> =
|
|||||||
| LedgerDataResponse
|
| LedgerDataResponse
|
||||||
| LedgerEntryResponse
|
| LedgerEntryResponse
|
||||||
// transaction methods
|
// transaction methods
|
||||||
|
| SimulateResponse
|
||||||
| SubmitResponse
|
| SubmitResponse
|
||||||
| SubmitMultisignedVersionResponseMap<Version>
|
| SubmitMultisignedVersionResponseMap<Version>
|
||||||
| TransactionEntryResponse
|
| TransactionEntryResponse
|
||||||
@@ -398,6 +408,12 @@ export type RequestResponseMap<
|
|||||||
? LedgerDataResponse
|
? LedgerDataResponse
|
||||||
: T extends LedgerEntryRequest
|
: T extends LedgerEntryRequest
|
||||||
? LedgerEntryResponse
|
? LedgerEntryResponse
|
||||||
|
: T extends SimulateBinaryRequest
|
||||||
|
? SimulateBinaryResponse
|
||||||
|
: T extends SimulateJsonRequest
|
||||||
|
? SimulateJsonResponse
|
||||||
|
: T extends SimulateRequest
|
||||||
|
? SimulateJsonResponse
|
||||||
: T extends SubmitRequest
|
: T extends SubmitRequest
|
||||||
? SubmitResponse
|
? SubmitResponse
|
||||||
: T extends SubmitMultisignedRequest
|
: T extends SubmitMultisignedRequest
|
||||||
@@ -544,6 +560,8 @@ export {
|
|||||||
LedgerEntryRequest,
|
LedgerEntryRequest,
|
||||||
LedgerEntryResponse,
|
LedgerEntryResponse,
|
||||||
// transaction methods with types
|
// transaction methods with types
|
||||||
|
SimulateRequest,
|
||||||
|
SimulateResponse,
|
||||||
SubmitRequest,
|
SubmitRequest,
|
||||||
SubmitResponse,
|
SubmitResponse,
|
||||||
SubmitMultisignedRequest,
|
SubmitMultisignedRequest,
|
||||||
|
|||||||
@@ -203,13 +203,13 @@ export interface LedgerQueueData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LedgerBinary
|
export interface LedgerBinary
|
||||||
extends Omit<Omit<Ledger, 'transactions'>, 'accountState'> {
|
extends Omit<Ledger, 'transactions' | 'accountState'> {
|
||||||
accountState?: string[]
|
accountState?: string[]
|
||||||
transactions?: string[]
|
transactions?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LedgerBinaryV1
|
export interface LedgerBinaryV1
|
||||||
extends Omit<Omit<LedgerV1, 'transactions'>, 'accountState'> {
|
extends Omit<LedgerV1, 'transactions' | 'accountState'> {
|
||||||
accountState?: string[]
|
accountState?: string[]
|
||||||
transactions?: string[]
|
transactions?: string[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ export interface ServerStateResponse extends BaseResponse {
|
|||||||
load_factor_fee_queue?: number
|
load_factor_fee_queue?: number
|
||||||
load_factor_fee_reference?: number
|
load_factor_fee_reference?: number
|
||||||
load_factor_server?: number
|
load_factor_server?: number
|
||||||
|
network_id: number
|
||||||
peer_disconnects?: string
|
peer_disconnects?: string
|
||||||
peer_disconnects_resources?: string
|
peer_disconnects_resources?: string
|
||||||
peers: number
|
peers: number
|
||||||
|
|||||||
88
packages/xrpl/src/models/methods/simulate.ts
Normal file
88
packages/xrpl/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>
|
||||||
|
}
|
||||||
|
}
|
||||||
120
packages/xrpl/src/models/transactions/AMMClawback.ts
Normal file
120
packages/xrpl/src/models/transactions/AMMClawback.ts
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
import { ValidationError } from '../../errors'
|
||||||
|
import { Currency, IssuedCurrency, IssuedCurrencyAmount } from '../common'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Account,
|
||||||
|
BaseTransaction,
|
||||||
|
GlobalFlags,
|
||||||
|
isAccount,
|
||||||
|
isAmount,
|
||||||
|
isCurrency,
|
||||||
|
validateBaseTransaction,
|
||||||
|
validateOptionalField,
|
||||||
|
validateRequiredField,
|
||||||
|
} from './common'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing values for AMMClawback Transaction Flags.
|
||||||
|
*
|
||||||
|
* @category Transaction Flags
|
||||||
|
*/
|
||||||
|
export enum AMMClawbackFlags {
|
||||||
|
tfClawTwoAssets = 0x00000001,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of flags to boolean values representing {@link AMMClawback} transaction
|
||||||
|
* flags.
|
||||||
|
*
|
||||||
|
* @category Transaction Flags
|
||||||
|
*/
|
||||||
|
export interface AMMClawbackFlagsInterface extends GlobalFlags {
|
||||||
|
tfClawTwoAssets?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Claw back tokens from a holder that has deposited your issued tokens into an AMM pool.
|
||||||
|
*
|
||||||
|
* Clawback is disabled by default. To use clawback, you must send an AccountSet transaction to enable the
|
||||||
|
* Allow Trust Line Clawback setting. An issuer with any existing tokens cannot enable clawback. You can
|
||||||
|
* only enable Allow Trust Line Clawback if you have a completely empty owner directory, meaning you must
|
||||||
|
* do so before you set up any trust lines, offers, escrows, payment channels, checks, or signer lists.
|
||||||
|
* After you enable clawback, it cannot reverted: the account permanently gains the ability to claw back
|
||||||
|
* issued assets on trust lines.
|
||||||
|
*/
|
||||||
|
export interface AMMClawback extends BaseTransaction {
|
||||||
|
TransactionType: 'AMMClawback'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The account holding the asset to be clawed back.
|
||||||
|
*/
|
||||||
|
Holder: Account
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the asset that the issuer wants to claw back from the AMM pool.
|
||||||
|
* In JSON, this is an object with currency and issuer fields. The issuer field must match with Account.
|
||||||
|
*/
|
||||||
|
Asset: IssuedCurrency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the other asset in the AMM's pool. In JSON, this is an object with currency and
|
||||||
|
* issuer fields (omit issuer for XRP).
|
||||||
|
*/
|
||||||
|
Asset2: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum amount to claw back from the AMM account. The currency and issuer subfields should match
|
||||||
|
* the Asset subfields. If this field isn't specified, or the value subfield exceeds the holder's available
|
||||||
|
* tokens in the AMM, all of the holder's tokens will be clawed back.
|
||||||
|
*/
|
||||||
|
Amount?: IssuedCurrencyAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of an AMMClawback at runtime.
|
||||||
|
*
|
||||||
|
* @param tx - An AMMClawback Transaction.
|
||||||
|
* @throws {ValidationError} When the transaction is malformed.
|
||||||
|
*/
|
||||||
|
export function validateAMMClawback(tx: Record<string, unknown>): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
validateRequiredField(tx, 'Holder', isAccount)
|
||||||
|
|
||||||
|
validateRequiredField(tx, 'Asset', isCurrency)
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- required
|
||||||
|
const asset = tx.Asset as IssuedCurrency
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- required
|
||||||
|
const amount = tx.Amount as IssuedCurrencyAmount
|
||||||
|
|
||||||
|
if (tx.Holder === asset.issuer) {
|
||||||
|
throw new ValidationError(
|
||||||
|
'AMMClawback: Holder and Asset.issuer must be distinct',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Account !== asset.issuer) {
|
||||||
|
throw new ValidationError(
|
||||||
|
'AMMClawback: Account must be the same as Asset.issuer',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
validateRequiredField(tx, 'Asset2', isCurrency)
|
||||||
|
|
||||||
|
validateOptionalField(tx, 'Amount', isAmount)
|
||||||
|
|
||||||
|
if (tx.Amount != null) {
|
||||||
|
if (amount.currency !== asset.currency) {
|
||||||
|
throw new ValidationError(
|
||||||
|
'AMMClawback: Amount.currency must match Asset.currency',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount.issuer !== asset.issuer) {
|
||||||
|
throw new ValidationError(
|
||||||
|
'AMMClawback: Amount.issuer must match Amount.issuer',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,6 +38,10 @@ export enum NFTokenMintFlags {
|
|||||||
* issuer.
|
* issuer.
|
||||||
*/
|
*/
|
||||||
tfTransferable = 0x00000008,
|
tfTransferable = 0x00000008,
|
||||||
|
/**
|
||||||
|
* If set, indicates that this NFT's URI can be modified.
|
||||||
|
*/
|
||||||
|
tfMutable = 0x00000010,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,6 +55,7 @@ export interface NFTokenMintFlagsInterface extends GlobalFlags {
|
|||||||
tfOnlyXRP?: boolean
|
tfOnlyXRP?: boolean
|
||||||
tfTrustLine?: boolean
|
tfTrustLine?: boolean
|
||||||
tfTransferable?: boolean
|
tfTransferable?: boolean
|
||||||
|
tfMutable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
67
packages/xrpl/src/models/transactions/NFTokenModify.ts
Normal file
67
packages/xrpl/src/models/transactions/NFTokenModify.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { ValidationError } from '../../errors'
|
||||||
|
import { isHex } from '../utils'
|
||||||
|
|
||||||
|
import {
|
||||||
|
BaseTransaction,
|
||||||
|
validateBaseTransaction,
|
||||||
|
isAccount,
|
||||||
|
isString,
|
||||||
|
validateOptionalField,
|
||||||
|
Account,
|
||||||
|
validateRequiredField,
|
||||||
|
} from './common'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The NFTokenModify transaction modifies an NFToken's URI
|
||||||
|
* if its tfMutable is set to true.
|
||||||
|
*/
|
||||||
|
export interface NFTokenModify extends BaseTransaction {
|
||||||
|
TransactionType: 'NFTokenModify'
|
||||||
|
/**
|
||||||
|
* Identifies the NFTokenID of the NFToken object that the
|
||||||
|
* offer references.
|
||||||
|
*/
|
||||||
|
NFTokenID: string
|
||||||
|
/**
|
||||||
|
* Indicates the AccountID of the account that owns the corresponding NFToken.
|
||||||
|
* Can be omitted if the owner is the account submitting this transaction
|
||||||
|
*/
|
||||||
|
Owner?: Account
|
||||||
|
/**
|
||||||
|
* URI that points to the data and/or metadata associated with the NFT.
|
||||||
|
* This field need not be an HTTP or HTTPS URL; it could be an IPFS URI, a
|
||||||
|
* magnet link, immediate data encoded as an RFC2379 "data" URL, or even an
|
||||||
|
* opaque issuer-specific encoding. The URI is NOT checked for validity, but
|
||||||
|
* the field is limited to a maximum length of 256 bytes.
|
||||||
|
*
|
||||||
|
* This field must be hex-encoded. You can use `convertStringToHex` to
|
||||||
|
* convert this field to the proper encoding.
|
||||||
|
*
|
||||||
|
* This field must not be an empty string. Omit it from the transaction or
|
||||||
|
* set to `null` if you do not use it.
|
||||||
|
*/
|
||||||
|
URI?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of an NFTokenModify at runtime.
|
||||||
|
*
|
||||||
|
* @param tx - An NFTokenModify Transaction.
|
||||||
|
* @throws When the NFTokenModify is Malformed.
|
||||||
|
*/
|
||||||
|
export function validateNFTokenModify(tx: Record<string, unknown>): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
validateRequiredField(tx, 'NFTokenID', isString)
|
||||||
|
validateOptionalField(tx, 'Owner', isAccount)
|
||||||
|
validateOptionalField(tx, 'URI', isString)
|
||||||
|
|
||||||
|
if (tx.URI !== undefined && typeof tx.URI === 'string') {
|
||||||
|
if (tx.URI === '') {
|
||||||
|
throw new ValidationError('NFTokenModify: URI must not be empty string')
|
||||||
|
}
|
||||||
|
if (!isHex(tx.URI)) {
|
||||||
|
throw new ValidationError('NFTokenModify: URI must be in hex format')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
validateCredentialsList,
|
validateCredentialsList,
|
||||||
validateOptionalField,
|
validateOptionalField,
|
||||||
validateRequiredField,
|
validateRequiredField,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
} from './common'
|
} from './common'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,5 +55,6 @@ export function validateAccountDelete(tx: Record<string, unknown>): void {
|
|||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
|
||||||
tx.TransactionType as string,
|
tx.TransactionType as string,
|
||||||
true,
|
true,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ import {
|
|||||||
AuthorizeCredential,
|
AuthorizeCredential,
|
||||||
Currency,
|
Currency,
|
||||||
IssuedCurrencyAmount,
|
IssuedCurrencyAmount,
|
||||||
|
MPTAmount,
|
||||||
Memo,
|
Memo,
|
||||||
Signer,
|
Signer,
|
||||||
XChainBridge,
|
XChainBridge,
|
||||||
MPTAmount,
|
|
||||||
} from '../common'
|
} from '../common'
|
||||||
import { onlyHasFields } from '../utils'
|
import { onlyHasFields } from '../utils'
|
||||||
|
|
||||||
const MEMO_SIZE = 3
|
const MEMO_SIZE = 3
|
||||||
const MAX_CREDENTIALS_LIST_LENGTH = 8
|
export const MAX_AUTHORIZED_CREDENTIALS = 8
|
||||||
const MAX_CREDENTIAL_BYTE_LENGTH = 64
|
const MAX_CREDENTIAL_BYTE_LENGTH = 64
|
||||||
const MAX_CREDENTIAL_TYPE_LENGTH = MAX_CREDENTIAL_BYTE_LENGTH * 2
|
const MAX_CREDENTIAL_TYPE_LENGTH = MAX_CREDENTIAL_BYTE_LENGTH * 2
|
||||||
|
|
||||||
@@ -134,7 +134,9 @@ export function isIssuedCurrency(
|
|||||||
* @param input - The input to check the form and type of
|
* @param input - The input to check the form and type of
|
||||||
* @returns Whether the AuthorizeCredential is properly formed
|
* @returns Whether the AuthorizeCredential is properly formed
|
||||||
*/
|
*/
|
||||||
function isAuthorizeCredential(input: unknown): input is AuthorizeCredential {
|
export function isAuthorizeCredential(
|
||||||
|
input: unknown,
|
||||||
|
): input is AuthorizeCredential {
|
||||||
return (
|
return (
|
||||||
isRecord(input) &&
|
isRecord(input) &&
|
||||||
isRecord(input.Credential) &&
|
isRecord(input.Credential) &&
|
||||||
@@ -455,13 +457,16 @@ export function validateCredentialType(tx: Record<string, unknown>): void {
|
|||||||
* @param credentials An array of credential IDs to check for errors
|
* @param credentials An array of credential IDs to check for errors
|
||||||
* @param transactionType The transaction type to include in error messages
|
* @param transactionType The transaction type to include in error messages
|
||||||
* @param isStringID Toggle for if array contains IDs instead of AuthorizeCredential objects
|
* @param isStringID Toggle for if array contains IDs instead of AuthorizeCredential objects
|
||||||
|
* @param maxCredentials The maximum length of the credentials array.
|
||||||
|
* PermissionedDomainSet transaction uses 10, other transactions use 8.
|
||||||
* @throws Validation Error if the formatting is incorrect
|
* @throws Validation Error if the formatting is incorrect
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line max-lines-per-function -- separating logic further will add unnecessary complexity
|
// eslint-disable-next-line max-lines-per-function, max-params -- separating logic further will add unnecessary complexity
|
||||||
export function validateCredentialsList(
|
export function validateCredentialsList(
|
||||||
credentials: unknown,
|
credentials: unknown,
|
||||||
transactionType: string,
|
transactionType: string,
|
||||||
isStringID: boolean,
|
isStringID: boolean,
|
||||||
|
maxCredentials: number,
|
||||||
): void {
|
): void {
|
||||||
if (credentials == null) {
|
if (credentials == null) {
|
||||||
return
|
return
|
||||||
@@ -471,9 +476,9 @@ export function validateCredentialsList(
|
|||||||
`${transactionType}: Credentials must be an array`,
|
`${transactionType}: Credentials must be an array`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (credentials.length > MAX_CREDENTIALS_LIST_LENGTH) {
|
if (credentials.length > maxCredentials) {
|
||||||
throw new ValidationError(
|
throw new ValidationError(
|
||||||
`${transactionType}: Credentials length cannot exceed ${MAX_CREDENTIALS_LIST_LENGTH} elements`,
|
`${transactionType}: Credentials length cannot exceed ${maxCredentials} elements`,
|
||||||
)
|
)
|
||||||
} else if (credentials.length === 0) {
|
} else if (credentials.length === 0) {
|
||||||
throw new ValidationError(
|
throw new ValidationError(
|
||||||
@@ -500,7 +505,42 @@ export function validateCredentialsList(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function containsDuplicates(objectList: object[]): boolean {
|
// Type guard to ensure we're working with AuthorizeCredential[]
|
||||||
const objSet = new Set(objectList.map((obj) => JSON.stringify(obj)))
|
// Note: This is not a rigorous type-guard. A more thorough solution would be to iterate over the array and check each item.
|
||||||
return objSet.size !== objectList.length
|
function isAuthorizeCredentialArray(
|
||||||
|
list: AuthorizeCredential[] | string[],
|
||||||
|
): list is AuthorizeCredential[] {
|
||||||
|
return typeof list[0] !== 'string'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an array of objects contains any duplicates.
|
||||||
|
*
|
||||||
|
* @param objectList - Array of objects to check for duplicates
|
||||||
|
* @returns True if duplicates exist, false otherwise
|
||||||
|
*/
|
||||||
|
export function containsDuplicates(
|
||||||
|
objectList: AuthorizeCredential[] | string[],
|
||||||
|
): boolean {
|
||||||
|
// Case-1: Process a list of string-IDs
|
||||||
|
if (typeof objectList[0] === 'string') {
|
||||||
|
const objSet = new Set(objectList.map((obj) => JSON.stringify(obj)))
|
||||||
|
return objSet.size !== objectList.length
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case-2: Process a list of nested objects
|
||||||
|
const seen = new Set<string>()
|
||||||
|
|
||||||
|
if (isAuthorizeCredentialArray(objectList)) {
|
||||||
|
for (const item of objectList) {
|
||||||
|
const key = `${item.Credential.Issuer}-${item.Credential.CredentialType}`
|
||||||
|
// eslint-disable-next-line max-depth -- necessary to check for type-guards
|
||||||
|
if (seen.has(key)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
seen.add(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
BaseTransaction,
|
BaseTransaction,
|
||||||
validateBaseTransaction,
|
validateBaseTransaction,
|
||||||
validateCredentialsList,
|
validateCredentialsList,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
} from './common'
|
} from './common'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,6 +73,7 @@ export function validateDepositPreauth(tx: Record<string, unknown>): void {
|
|||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check
|
||||||
tx.TransactionType as string,
|
tx.TransactionType as string,
|
||||||
false,
|
false,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
)
|
)
|
||||||
} else if (tx.UnauthorizeCredentials !== undefined) {
|
} else if (tx.UnauthorizeCredentials !== undefined) {
|
||||||
validateCredentialsList(
|
validateCredentialsList(
|
||||||
@@ -79,6 +81,7 @@ export function validateDepositPreauth(tx: Record<string, unknown>): void {
|
|||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check
|
||||||
tx.TransactionType as string,
|
tx.TransactionType as string,
|
||||||
false,
|
false,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
validateBaseTransaction,
|
validateBaseTransaction,
|
||||||
validateCredentialsList,
|
validateCredentialsList,
|
||||||
validateRequiredField,
|
validateRequiredField,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
} from './common'
|
} from './common'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +56,7 @@ export function validateEscrowFinish(tx: Record<string, unknown>): void {
|
|||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
|
||||||
tx.TransactionType as string,
|
tx.TransactionType as string,
|
||||||
true,
|
true,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (tx.OfferSequence == null) {
|
if (tx.OfferSequence == null) {
|
||||||
|
|||||||
@@ -15,13 +15,18 @@ export {
|
|||||||
} from './accountSet'
|
} from './accountSet'
|
||||||
export { AccountDelete } from './accountDelete'
|
export { AccountDelete } from './accountDelete'
|
||||||
export { AMMBid } from './AMMBid'
|
export { AMMBid } from './AMMBid'
|
||||||
|
export {
|
||||||
|
AMMClawbackFlags,
|
||||||
|
AMMClawbackFlagsInterface,
|
||||||
|
AMMClawback,
|
||||||
|
} from './AMMClawback'
|
||||||
|
export { AMMCreate } from './AMMCreate'
|
||||||
export { AMMDelete } from './AMMDelete'
|
export { AMMDelete } from './AMMDelete'
|
||||||
export {
|
export {
|
||||||
AMMDepositFlags,
|
AMMDepositFlags,
|
||||||
AMMDepositFlagsInterface,
|
AMMDepositFlagsInterface,
|
||||||
AMMDeposit,
|
AMMDeposit,
|
||||||
} from './AMMDeposit'
|
} from './AMMDeposit'
|
||||||
export { AMMCreate } from './AMMCreate'
|
|
||||||
export { AMMVote } from './AMMVote'
|
export { AMMVote } from './AMMVote'
|
||||||
export {
|
export {
|
||||||
AMMWithdrawFlags,
|
AMMWithdrawFlags,
|
||||||
@@ -71,6 +76,7 @@ export {
|
|||||||
NFTokenMintFlags,
|
NFTokenMintFlags,
|
||||||
NFTokenMintFlagsInterface,
|
NFTokenMintFlagsInterface,
|
||||||
} from './NFTokenMint'
|
} from './NFTokenMint'
|
||||||
|
export { NFTokenModify, validateNFTokenModify } from './NFTokenModify'
|
||||||
export { OfferCancel } from './offerCancel'
|
export { OfferCancel } from './offerCancel'
|
||||||
export {
|
export {
|
||||||
OfferCreateFlags,
|
OfferCreateFlags,
|
||||||
@@ -105,3 +111,6 @@ export {
|
|||||||
XChainModifyBridgeFlags,
|
XChainModifyBridgeFlags,
|
||||||
XChainModifyBridgeFlagsInterface,
|
XChainModifyBridgeFlagsInterface,
|
||||||
} from './XChainModifyBridge'
|
} from './XChainModifyBridge'
|
||||||
|
|
||||||
|
export { PermissionedDomainSet } from './permissionedDomainSet'
|
||||||
|
export { PermissionedDomainDelete } from './permissionedDomainDelete'
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
isNumber,
|
isNumber,
|
||||||
Account,
|
Account,
|
||||||
validateCredentialsList,
|
validateCredentialsList,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
} from './common'
|
} from './common'
|
||||||
import type { TransactionMetadataBase } from './metadata'
|
import type { TransactionMetadataBase } from './metadata'
|
||||||
|
|
||||||
@@ -188,6 +189,7 @@ export function validatePayment(tx: Record<string, unknown>): void {
|
|||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
|
||||||
tx.TransactionType as string,
|
tx.TransactionType as string,
|
||||||
true,
|
true,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (tx.InvoiceID !== undefined && typeof tx.InvoiceID !== 'string') {
|
if (tx.InvoiceID !== undefined && typeof tx.InvoiceID !== 'string') {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
GlobalFlags,
|
GlobalFlags,
|
||||||
validateBaseTransaction,
|
validateBaseTransaction,
|
||||||
validateCredentialsList,
|
validateCredentialsList,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
} from './common'
|
} from './common'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -153,6 +154,7 @@ export function validatePaymentChannelClaim(tx: Record<string, unknown>): void {
|
|||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
|
||||||
tx.TransactionType as string,
|
tx.TransactionType as string,
|
||||||
true,
|
true,
|
||||||
|
MAX_AUTHORIZED_CREDENTIALS,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (tx.Channel === undefined) {
|
if (tx.Channel === undefined) {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import {
|
||||||
|
BaseTransaction,
|
||||||
|
isString,
|
||||||
|
validateBaseTransaction,
|
||||||
|
validateRequiredField,
|
||||||
|
} from './common'
|
||||||
|
|
||||||
|
export interface PermissionedDomainDelete extends BaseTransaction {
|
||||||
|
/* The transaction type (PermissionedDomainDelete). */
|
||||||
|
TransactionType: 'PermissionedDomainDelete'
|
||||||
|
|
||||||
|
/* The domain to delete. */
|
||||||
|
DomainID: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of a PermissionedDomainDelete transaction.
|
||||||
|
*
|
||||||
|
* @param tx - The transaction to verify.
|
||||||
|
* @throws When the transaction is malformed.
|
||||||
|
*/
|
||||||
|
export function validatePermissionedDomainDelete(
|
||||||
|
tx: Record<string, unknown>,
|
||||||
|
): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
validateRequiredField(tx, 'DomainID', isString)
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { AuthorizeCredential } from '../common'
|
||||||
|
|
||||||
|
import {
|
||||||
|
BaseTransaction,
|
||||||
|
isString,
|
||||||
|
validateBaseTransaction,
|
||||||
|
validateOptionalField,
|
||||||
|
validateRequiredField,
|
||||||
|
validateCredentialsList,
|
||||||
|
} from './common'
|
||||||
|
|
||||||
|
const MAX_ACCEPTED_CREDENTIALS = 10
|
||||||
|
|
||||||
|
export interface PermissionedDomainSet extends BaseTransaction {
|
||||||
|
/* The transaction type (PermissionedDomainSet). */
|
||||||
|
TransactionType: 'PermissionedDomainSet'
|
||||||
|
|
||||||
|
/* The domain to modify. Must be included if modifying an existing domain. */
|
||||||
|
DomainID?: string
|
||||||
|
|
||||||
|
/* The credentials that are accepted by the domain. Ownership of one
|
||||||
|
of these credentials automatically makes you a member of the domain.
|
||||||
|
An empty array means deleting the field. */
|
||||||
|
AcceptedCredentials: AuthorizeCredential[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a PermissionedDomainSet transaction.
|
||||||
|
*
|
||||||
|
* @param tx - The transaction to validate.
|
||||||
|
* @throws {ValidationError} When the transaction is invalid.
|
||||||
|
*/
|
||||||
|
export function validatePermissionedDomainSet(
|
||||||
|
tx: Record<string, unknown>,
|
||||||
|
): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
validateOptionalField(tx, 'DomainID', isString)
|
||||||
|
validateRequiredField(
|
||||||
|
tx,
|
||||||
|
'AcceptedCredentials',
|
||||||
|
() => tx.AcceptedCredentials instanceof Array,
|
||||||
|
)
|
||||||
|
|
||||||
|
validateCredentialsList(
|
||||||
|
tx.AcceptedCredentials,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
|
||||||
|
tx.TransactionType as string,
|
||||||
|
// PermissionedDomainSet uses AuthorizeCredential nested objects only, strings are not allowed
|
||||||
|
false,
|
||||||
|
// PermissionedDomainSet uses at most 10 accepted credentials. This is different from Credential-feature transactions.
|
||||||
|
MAX_ACCEPTED_CREDENTIALS,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -4,11 +4,12 @@
|
|||||||
import { ValidationError } from '../../errors'
|
import { ValidationError } from '../../errors'
|
||||||
import { IssuedCurrencyAmount, Memo } from '../common'
|
import { IssuedCurrencyAmount, Memo } from '../common'
|
||||||
import { isHex } from '../utils'
|
import { isHex } from '../utils'
|
||||||
import { setTransactionFlagsToNumber } from '../utils/flags'
|
import { convertTxFlagsToNumber } from '../utils/flags'
|
||||||
|
|
||||||
import { AccountDelete, validateAccountDelete } from './accountDelete'
|
import { AccountDelete, validateAccountDelete } from './accountDelete'
|
||||||
import { AccountSet, validateAccountSet } from './accountSet'
|
import { AccountSet, validateAccountSet } from './accountSet'
|
||||||
import { AMMBid, validateAMMBid } from './AMMBid'
|
import { AMMBid, validateAMMBid } from './AMMBid'
|
||||||
|
import { AMMClawback, validateAMMClawback } from './AMMClawback'
|
||||||
import { AMMCreate, validateAMMCreate } from './AMMCreate'
|
import { AMMCreate, validateAMMCreate } from './AMMCreate'
|
||||||
import { AMMDelete, validateAMMDelete } from './AMMDelete'
|
import { AMMDelete, validateAMMDelete } from './AMMDelete'
|
||||||
import { AMMDeposit, validateAMMDeposit } from './AMMDeposit'
|
import { AMMDeposit, validateAMMDeposit } from './AMMDeposit'
|
||||||
@@ -57,6 +58,7 @@ import {
|
|||||||
validateNFTokenCreateOffer,
|
validateNFTokenCreateOffer,
|
||||||
} from './NFTokenCreateOffer'
|
} from './NFTokenCreateOffer'
|
||||||
import { NFTokenMint, validateNFTokenMint } from './NFTokenMint'
|
import { NFTokenMint, validateNFTokenMint } from './NFTokenMint'
|
||||||
|
import { NFTokenModify, validateNFTokenModify } from './NFTokenModify'
|
||||||
import { OfferCancel, validateOfferCancel } from './offerCancel'
|
import { OfferCancel, validateOfferCancel } from './offerCancel'
|
||||||
import { OfferCreate, validateOfferCreate } from './offerCreate'
|
import { OfferCreate, validateOfferCreate } from './offerCreate'
|
||||||
import { OracleDelete, validateOracleDelete } from './oracleDelete'
|
import { OracleDelete, validateOracleDelete } from './oracleDelete'
|
||||||
@@ -74,6 +76,14 @@ import {
|
|||||||
PaymentChannelFund,
|
PaymentChannelFund,
|
||||||
validatePaymentChannelFund,
|
validatePaymentChannelFund,
|
||||||
} from './paymentChannelFund'
|
} from './paymentChannelFund'
|
||||||
|
import {
|
||||||
|
PermissionedDomainDelete,
|
||||||
|
validatePermissionedDomainDelete,
|
||||||
|
} from './permissionedDomainDelete'
|
||||||
|
import {
|
||||||
|
PermissionedDomainSet,
|
||||||
|
validatePermissionedDomainSet,
|
||||||
|
} from './permissionedDomainSet'
|
||||||
import { SetFee } from './setFee'
|
import { SetFee } from './setFee'
|
||||||
import { SetRegularKey, validateSetRegularKey } from './setRegularKey'
|
import { SetRegularKey, validateSetRegularKey } from './setRegularKey'
|
||||||
import { SignerListSet, validateSignerListSet } from './signerListSet'
|
import { SignerListSet, validateSignerListSet } from './signerListSet'
|
||||||
@@ -114,6 +124,7 @@ import {
|
|||||||
*/
|
*/
|
||||||
export type SubmittableTransaction =
|
export type SubmittableTransaction =
|
||||||
| AMMBid
|
| AMMBid
|
||||||
|
| AMMClawback
|
||||||
| AMMCreate
|
| AMMCreate
|
||||||
| AMMDelete
|
| AMMDelete
|
||||||
| AMMDeposit
|
| AMMDeposit
|
||||||
@@ -143,6 +154,7 @@ export type SubmittableTransaction =
|
|||||||
| NFTokenCancelOffer
|
| NFTokenCancelOffer
|
||||||
| NFTokenCreateOffer
|
| NFTokenCreateOffer
|
||||||
| NFTokenMint
|
| NFTokenMint
|
||||||
|
| NFTokenModify
|
||||||
| OfferCancel
|
| OfferCancel
|
||||||
| OfferCreate
|
| OfferCreate
|
||||||
| OracleDelete
|
| OracleDelete
|
||||||
@@ -151,6 +163,8 @@ export type SubmittableTransaction =
|
|||||||
| PaymentChannelClaim
|
| PaymentChannelClaim
|
||||||
| PaymentChannelCreate
|
| PaymentChannelCreate
|
||||||
| PaymentChannelFund
|
| PaymentChannelFund
|
||||||
|
| PermissionedDomainSet
|
||||||
|
| PermissionedDomainDelete
|
||||||
| SetRegularKey
|
| SetRegularKey
|
||||||
| SignerListSet
|
| SignerListSet
|
||||||
| TicketCreate
|
| TicketCreate
|
||||||
@@ -255,12 +269,16 @@ export function validate(transaction: Record<string, unknown>): void {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- okay here
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- okay here
|
||||||
setTransactionFlagsToNumber(tx as unknown as Transaction)
|
tx.Flags = convertTxFlagsToNumber(tx as unknown as Transaction)
|
||||||
switch (tx.TransactionType) {
|
switch (tx.TransactionType) {
|
||||||
case 'AMMBid':
|
case 'AMMBid':
|
||||||
validateAMMBid(tx)
|
validateAMMBid(tx)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case 'AMMClawback':
|
||||||
|
validateAMMClawback(tx)
|
||||||
|
break
|
||||||
|
|
||||||
case 'AMMCreate':
|
case 'AMMCreate':
|
||||||
validateAMMCreate(tx)
|
validateAMMCreate(tx)
|
||||||
break
|
break
|
||||||
@@ -377,6 +395,10 @@ export function validate(transaction: Record<string, unknown>): void {
|
|||||||
validateNFTokenMint(tx)
|
validateNFTokenMint(tx)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case 'NFTokenModify':
|
||||||
|
validateNFTokenModify(tx)
|
||||||
|
break
|
||||||
|
|
||||||
case 'OfferCancel':
|
case 'OfferCancel':
|
||||||
validateOfferCancel(tx)
|
validateOfferCancel(tx)
|
||||||
break
|
break
|
||||||
@@ -409,6 +431,14 @@ export function validate(transaction: Record<string, unknown>): void {
|
|||||||
validatePaymentChannelFund(tx)
|
validatePaymentChannelFund(tx)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case 'PermissionedDomainSet':
|
||||||
|
validatePermissionedDomainSet(tx)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'PermissionedDomainDelete':
|
||||||
|
validatePermissionedDomainDelete(tx)
|
||||||
|
break
|
||||||
|
|
||||||
case 'SetRegularKey':
|
case 'SetRegularKey':
|
||||||
validateSetRegularKey(tx)
|
validateSetRegularKey(tx)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ export enum TrustSetFlags {
|
|||||||
tfSetFreeze = 0x00100000,
|
tfSetFreeze = 0x00100000,
|
||||||
/** Unfreeze the trust line. */
|
/** Unfreeze the trust line. */
|
||||||
tfClearFreeze = 0x00200000,
|
tfClearFreeze = 0x00200000,
|
||||||
|
/** Deep-Freeze the trustline -- disallow sending and receiving the said IssuedCurrency */
|
||||||
|
/** Allowed only if the trustline is already regularly frozen, or if tfSetFreeze is set in the same transaction. */
|
||||||
|
tfSetDeepFreeze = 0x00400000,
|
||||||
|
/** Clear a Deep-Frozen trustline */
|
||||||
|
tfClearDeepFreeze = 0x00800000,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,6 +94,11 @@ export interface TrustSetFlagsInterface extends GlobalFlags {
|
|||||||
tfSetFreeze?: boolean
|
tfSetFreeze?: boolean
|
||||||
/** Unfreeze the trust line. */
|
/** Unfreeze the trust line. */
|
||||||
tfClearFreeze?: boolean
|
tfClearFreeze?: boolean
|
||||||
|
/** Deep-Freeze the trustline -- disallow sending and receiving the said IssuedCurrency */
|
||||||
|
/** Allowed only if the trustline is already regularly frozen, or if tfSetFreeze is set in the same transaction. */
|
||||||
|
tfSetDeepFreeze?: boolean
|
||||||
|
/** Clear a Deep-Frozen trust line */
|
||||||
|
tfClearDeepFreeze?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable no-param-reassign -- param reassign is safe */
|
|
||||||
/* eslint-disable no-bitwise -- flags require bitwise operations */
|
/* eslint-disable no-bitwise -- flags require bitwise operations */
|
||||||
import { ValidationError } from '../../errors'
|
import { ValidationError } from '../../errors'
|
||||||
import {
|
import {
|
||||||
@@ -6,9 +5,9 @@ import {
|
|||||||
AccountRootFlags,
|
AccountRootFlags,
|
||||||
} from '../ledger/AccountRoot'
|
} from '../ledger/AccountRoot'
|
||||||
import { AccountSetTfFlags } from '../transactions/accountSet'
|
import { AccountSetTfFlags } from '../transactions/accountSet'
|
||||||
|
import { AMMClawbackFlags } from '../transactions/AMMClawback'
|
||||||
import { AMMDepositFlags } from '../transactions/AMMDeposit'
|
import { AMMDepositFlags } from '../transactions/AMMDeposit'
|
||||||
import { AMMWithdrawFlags } from '../transactions/AMMWithdraw'
|
import { AMMWithdrawFlags } from '../transactions/AMMWithdraw'
|
||||||
import { GlobalFlags } from '../transactions/common'
|
|
||||||
import { MPTokenAuthorizeFlags } from '../transactions/MPTokenAuthorize'
|
import { MPTokenAuthorizeFlags } from '../transactions/MPTokenAuthorize'
|
||||||
import { MPTokenIssuanceCreateFlags } from '../transactions/MPTokenIssuanceCreate'
|
import { MPTokenIssuanceCreateFlags } from '../transactions/MPTokenIssuanceCreate'
|
||||||
import { MPTokenIssuanceSetFlags } from '../transactions/MPTokenIssuanceSet'
|
import { MPTokenIssuanceSetFlags } from '../transactions/MPTokenIssuanceSet'
|
||||||
@@ -49,6 +48,7 @@ export function parseAccountRootFlags(
|
|||||||
|
|
||||||
const txToFlag = {
|
const txToFlag = {
|
||||||
AccountSet: AccountSetTfFlags,
|
AccountSet: AccountSetTfFlags,
|
||||||
|
AMMClawback: AMMClawbackFlags,
|
||||||
AMMDeposit: AMMDepositFlags,
|
AMMDeposit: AMMDepositFlags,
|
||||||
AMMWithdraw: AMMWithdrawFlags,
|
AMMWithdraw: AMMWithdrawFlags,
|
||||||
MPTokenAuthorize: MPTokenAuthorizeFlags,
|
MPTokenAuthorize: MPTokenAuthorizeFlags,
|
||||||
@@ -63,37 +63,61 @@ const txToFlag = {
|
|||||||
XChainModifyBridge: XChainModifyBridgeFlags,
|
XChainModifyBridge: XChainModifyBridgeFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isTxToFlagKey(
|
||||||
|
transactionType: string,
|
||||||
|
): transactionType is keyof typeof txToFlag {
|
||||||
|
return transactionType in txToFlag
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a transaction's flags to its numeric representation.
|
* Sets a transaction's flags to its numeric representation.
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
|
* This utility function is deprecated.
|
||||||
|
* Use convertTxFlagsToNumber() instead and use the returned value to modify the Transaction.Flags from the caller.
|
||||||
|
*
|
||||||
* @param tx - A transaction to set its flags to its numeric representation.
|
* @param tx - A transaction to set its flags to its numeric representation.
|
||||||
*/
|
*/
|
||||||
export function setTransactionFlagsToNumber(tx: Transaction): void {
|
export function setTransactionFlagsToNumber(tx: Transaction): void {
|
||||||
if (tx.Flags == null) {
|
// eslint-disable-next-line no-console -- intended deprecation warning
|
||||||
tx.Flags = 0
|
console.warn(
|
||||||
return
|
'This function is deprecated. Use convertTxFlagsToNumber() instead and use the returned value to modify the Transaction.Flags from the caller.',
|
||||||
}
|
)
|
||||||
if (typeof tx.Flags === 'number') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.Flags = txToFlag[tx.TransactionType]
|
if (tx.Flags) {
|
||||||
? convertFlagsToNumber(tx.Flags, txToFlag[tx.TransactionType])
|
// eslint-disable-next-line no-param-reassign -- intended param reassign in setter, retain old functionality for compatibility
|
||||||
: 0
|
tx.Flags = convertTxFlagsToNumber(tx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- added ValidationError check for flagEnum
|
/**
|
||||||
function convertFlagsToNumber(flags: GlobalFlags, flagEnum: any): number {
|
* Returns a Transaction's Flags as its numeric representation.
|
||||||
return Object.keys(flags).reduce((resultFlags, flag) => {
|
*
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- safe member access
|
* @param tx - A Transaction to parse Flags for
|
||||||
if (flagEnum[flag] == null) {
|
* @returns A numerical representation of a Transaction's Flags
|
||||||
throw new ValidationError(
|
*/
|
||||||
`flag ${flag} doesn't exist in flagEnum: ${JSON.stringify(flagEnum)}`,
|
export function convertTxFlagsToNumber(tx: Transaction): number {
|
||||||
)
|
if (!tx.Flags) {
|
||||||
}
|
return 0
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- safe member access
|
}
|
||||||
return flags[flag] ? resultFlags | flagEnum[flag] : resultFlags
|
if (typeof tx.Flags === 'number') {
|
||||||
}, 0)
|
return tx.Flags
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTxToFlagKey(tx.TransactionType)) {
|
||||||
|
const flagEnum = txToFlag[tx.TransactionType]
|
||||||
|
return Object.keys(tx.Flags).reduce((resultFlags, flag) => {
|
||||||
|
if (flagEnum[flag] == null) {
|
||||||
|
throw new ValidationError(
|
||||||
|
`Invalid flag ${flag}. Valid flags are ${JSON.stringify(flagEnum)}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.Flags?.[flag] ? resultFlags | flagEnum[flag] : resultFlags
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,22 +127,24 @@ function convertFlagsToNumber(flags: GlobalFlags, flagEnum: any): number {
|
|||||||
* @returns A map with all flags as booleans.
|
* @returns A map with all flags as booleans.
|
||||||
*/
|
*/
|
||||||
export function parseTransactionFlags(tx: Transaction): object {
|
export function parseTransactionFlags(tx: Transaction): object {
|
||||||
setTransactionFlagsToNumber(tx)
|
const flags = convertTxFlagsToNumber(tx)
|
||||||
if (typeof tx.Flags !== 'number' || !tx.Flags || tx.Flags === 0) {
|
if (flags === 0) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const flags = tx.Flags
|
const booleanFlagMap = {}
|
||||||
const flagsMap = {}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- safe member access
|
if (isTxToFlagKey(tx.TransactionType)) {
|
||||||
const flagEnum = txToFlag[tx.TransactionType]
|
const transactionTypeFlags = txToFlag[tx.TransactionType]
|
||||||
Object.values(flagEnum).forEach((flag) => {
|
Object.values(transactionTypeFlags).forEach((flag) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- safe member access
|
if (
|
||||||
if (typeof flag === 'string' && isFlagEnabled(flags, flagEnum[flag])) {
|
typeof flag === 'string' &&
|
||||||
flagsMap[flag] = true
|
isFlagEnabled(flags, transactionTypeFlags[flag])
|
||||||
}
|
) {
|
||||||
})
|
booleanFlagMap[flag] = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return flagsMap
|
return booleanFlagMap
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { decode, encode } from 'ripple-binary-codec'
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
Client,
|
Client,
|
||||||
SubmitRequest,
|
SubmitRequest,
|
||||||
@@ -12,6 +10,7 @@ import { ValidationError, XrplError } from '../errors'
|
|||||||
import { Signer } from '../models/common'
|
import { Signer } from '../models/common'
|
||||||
import { TxResponse } from '../models/methods'
|
import { TxResponse } from '../models/methods'
|
||||||
import { BaseTransaction } from '../models/transactions/common'
|
import { BaseTransaction } from '../models/transactions/common'
|
||||||
|
import { decode, encode } from '../utils'
|
||||||
|
|
||||||
/** Approximate time for a ledger to close, in milliseconds */
|
/** Approximate time for a ledger to close, in milliseconds */
|
||||||
const LEDGER_CLOSE_TIME = 1000
|
const LEDGER_CLOSE_TIME = 1000
|
||||||
@@ -52,7 +51,7 @@ export async function submitRequest(
|
|||||||
failHard = false,
|
failHard = false,
|
||||||
): Promise<SubmitResponse> {
|
): Promise<SubmitResponse> {
|
||||||
if (!isSigned(signedTransaction)) {
|
if (!isSigned(signedTransaction)) {
|
||||||
throw new ValidationError('Transaction must be signed')
|
throw new ValidationError('Transaction must be signed.')
|
||||||
}
|
}
|
||||||
|
|
||||||
const signedTxEncoded =
|
const signedTxEncoded =
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ describe('server_info (rippled)', function () {
|
|||||||
'build_version',
|
'build_version',
|
||||||
'node_size',
|
'node_size',
|
||||||
'initial_sync_duration_us',
|
'initial_sync_duration_us',
|
||||||
|
'network_id',
|
||||||
|
'git',
|
||||||
]
|
]
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
omit(response.result.info, removeKeys),
|
omit(response.result.info, removeKeys),
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ describe('server_state', function () {
|
|||||||
load_factor_fee_queue: 256,
|
load_factor_fee_queue: 256,
|
||||||
load_factor_fee_reference: 256,
|
load_factor_fee_reference: 256,
|
||||||
load_factor_server: 256,
|
load_factor_server: 256,
|
||||||
|
network_id: 63456,
|
||||||
peer_disconnects: '0',
|
peer_disconnects: '0',
|
||||||
peer_disconnects_resources: '0',
|
peer_disconnects_resources: '0',
|
||||||
peers: 0,
|
peers: 0,
|
||||||
@@ -116,6 +117,8 @@ describe('server_state', function () {
|
|||||||
'node_size',
|
'node_size',
|
||||||
'initial_sync_duration_us',
|
'initial_sync_duration_us',
|
||||||
'ports',
|
'ports',
|
||||||
|
'git',
|
||||||
|
'network_id',
|
||||||
]
|
]
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
omit(response.result.state, removeKeys),
|
omit(response.result.state, removeKeys),
|
||||||
|
|||||||
85
packages/xrpl/test/integration/requests/simulate.test.ts
Normal file
85
packages/xrpl/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,
|
||||||
|
)
|
||||||
|
})
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { AMMClawback, AMMDeposit, AMMDepositFlags, XRP } from 'xrpl'
|
||||||
|
|
||||||
|
import serverUrl from '../serverUrl'
|
||||||
|
import {
|
||||||
|
setupClient,
|
||||||
|
teardownClient,
|
||||||
|
type XrplIntegrationTestContext,
|
||||||
|
} from '../setup'
|
||||||
|
import { createAMMPool, testTransaction } from '../utils'
|
||||||
|
|
||||||
|
describe('AMMClawback', function () {
|
||||||
|
let testContext: XrplIntegrationTestContext
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
testContext = await setupClient(serverUrl)
|
||||||
|
})
|
||||||
|
afterAll(async () => teardownClient(testContext))
|
||||||
|
|
||||||
|
it('base', async function () {
|
||||||
|
const ammPool = await createAMMPool(testContext.client, true)
|
||||||
|
const { issuerWallet } = ammPool
|
||||||
|
const holderWallet = ammPool.lpWallet
|
||||||
|
|
||||||
|
const asset = {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: issuerWallet.classicAddress,
|
||||||
|
}
|
||||||
|
const asset2 = {
|
||||||
|
currency: 'XRP',
|
||||||
|
} as XRP
|
||||||
|
|
||||||
|
const ammDepositTx: AMMDeposit = {
|
||||||
|
TransactionType: 'AMMDeposit',
|
||||||
|
Account: holderWallet.classicAddress,
|
||||||
|
Asset: asset,
|
||||||
|
Asset2: asset2,
|
||||||
|
Amount: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: issuerWallet.address,
|
||||||
|
value: '10',
|
||||||
|
},
|
||||||
|
Flags: AMMDepositFlags.tfSingleAsset,
|
||||||
|
}
|
||||||
|
|
||||||
|
await testTransaction(testContext.client, ammDepositTx, holderWallet)
|
||||||
|
|
||||||
|
const ammClawback: AMMClawback = {
|
||||||
|
TransactionType: 'AMMClawback',
|
||||||
|
Account: issuerWallet.address,
|
||||||
|
Holder: holderWallet.address,
|
||||||
|
Asset: asset,
|
||||||
|
Asset2: asset2,
|
||||||
|
}
|
||||||
|
|
||||||
|
await testTransaction(testContext.client, ammClawback, issuerWallet)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { NFTokenModify } from '../../../dist/npm'
|
||||||
|
import { NFTokenMintFlags } from '../../../dist/npm/src'
|
||||||
|
import {
|
||||||
|
convertStringToHex,
|
||||||
|
getNFTokenID,
|
||||||
|
NFTokenMint,
|
||||||
|
TransactionMetadata,
|
||||||
|
TxRequest,
|
||||||
|
} from '../../../src'
|
||||||
|
import { hashSignedTx } from '../../../src/utils/hashes'
|
||||||
|
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('NFTokenModify', function () {
|
||||||
|
let testContext: XrplIntegrationTestContext
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
testContext = await setupClient(serverUrl)
|
||||||
|
})
|
||||||
|
afterEach(async () => teardownClient(testContext))
|
||||||
|
|
||||||
|
// Mint an NFToken with tfMutable flag and modify URI later
|
||||||
|
it(
|
||||||
|
'modify NFToken URI',
|
||||||
|
async function () {
|
||||||
|
const oldUri = convertStringToHex('https://www.google.com')
|
||||||
|
const newUri = convertStringToHex('https://www.youtube.com')
|
||||||
|
|
||||||
|
const mutableMint: NFTokenMint = {
|
||||||
|
TransactionType: 'NFTokenMint',
|
||||||
|
Account: testContext.wallet.address,
|
||||||
|
Flags: NFTokenMintFlags.tfMutable,
|
||||||
|
URI: oldUri,
|
||||||
|
NFTokenTaxon: 0,
|
||||||
|
}
|
||||||
|
const response = await testTransaction(
|
||||||
|
testContext.client,
|
||||||
|
mutableMint,
|
||||||
|
testContext.wallet,
|
||||||
|
)
|
||||||
|
assert.equal(response.type, 'response')
|
||||||
|
|
||||||
|
const mutableTx: TxRequest = {
|
||||||
|
command: 'tx',
|
||||||
|
transaction: hashSignedTx(response.result.tx_blob),
|
||||||
|
}
|
||||||
|
const mutableTxResponse = await testContext.client.request(mutableTx)
|
||||||
|
|
||||||
|
const mutableNFTokenID =
|
||||||
|
getNFTokenID(
|
||||||
|
mutableTxResponse.result.meta as TransactionMetadata<NFTokenMint>,
|
||||||
|
) ?? 'undefined'
|
||||||
|
|
||||||
|
const accountNFTs = await testContext.client.request({
|
||||||
|
command: 'account_nfts',
|
||||||
|
account: testContext.wallet.address,
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
accountNFTs.result.account_nfts.find(
|
||||||
|
(nft) => nft.NFTokenID === mutableNFTokenID,
|
||||||
|
)?.URI,
|
||||||
|
oldUri,
|
||||||
|
)
|
||||||
|
|
||||||
|
const modifyTx: NFTokenModify = {
|
||||||
|
TransactionType: 'NFTokenModify',
|
||||||
|
Account: testContext.wallet.address,
|
||||||
|
NFTokenID: mutableNFTokenID,
|
||||||
|
URI: newUri,
|
||||||
|
}
|
||||||
|
|
||||||
|
const modifyResponse = await testTransaction(
|
||||||
|
testContext.client,
|
||||||
|
modifyTx,
|
||||||
|
testContext.wallet,
|
||||||
|
)
|
||||||
|
assert.equal(modifyResponse.type, 'response')
|
||||||
|
|
||||||
|
const nfts = await testContext.client.request({
|
||||||
|
command: 'account_nfts',
|
||||||
|
account: testContext.wallet.address,
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
nfts.result.account_nfts.find(
|
||||||
|
(nft) => nft.NFTokenID === mutableNFTokenID,
|
||||||
|
)?.URI,
|
||||||
|
newUri,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
TIMEOUT,
|
||||||
|
)
|
||||||
|
})
|
||||||
@@ -1,24 +1,36 @@
|
|||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
|
|
||||||
import { OfferCreate } from '../../../src'
|
import { OfferCreate, TrustSet, Wallet } from '../../../src'
|
||||||
import serverUrl from '../serverUrl'
|
import serverUrl from '../serverUrl'
|
||||||
import {
|
import {
|
||||||
setupClient,
|
setupClient,
|
||||||
teardownClient,
|
teardownClient,
|
||||||
type XrplIntegrationTestContext,
|
type XrplIntegrationTestContext,
|
||||||
} from '../setup'
|
} from '../setup'
|
||||||
import { testTransaction } from '../utils'
|
import {
|
||||||
|
testTransaction,
|
||||||
|
generateFundedWallet,
|
||||||
|
submitTransaction,
|
||||||
|
} from '../utils'
|
||||||
|
|
||||||
// how long before each test case times out
|
// how long before each test case times out
|
||||||
const TIMEOUT = 20000
|
const TIMEOUT = 20000
|
||||||
|
|
||||||
describe('OfferCreate', function () {
|
describe('OfferCreate', function () {
|
||||||
let testContext: XrplIntegrationTestContext
|
let testContext: XrplIntegrationTestContext
|
||||||
|
let wallet_deep_freeze_trustline: Wallet | undefined
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeAll(async () => {
|
||||||
testContext = await setupClient(serverUrl)
|
testContext = await setupClient(serverUrl)
|
||||||
|
if (!wallet_deep_freeze_trustline) {
|
||||||
|
// eslint-disable-next-line require-atomic-updates -- race condition doesn't really matter
|
||||||
|
wallet_deep_freeze_trustline = await generateFundedWallet(
|
||||||
|
testContext.client,
|
||||||
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
afterEach(async () => teardownClient(testContext))
|
|
||||||
|
afterAll(async () => teardownClient(testContext))
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'base',
|
'base',
|
||||||
@@ -49,4 +61,52 @@ describe('OfferCreate', function () {
|
|||||||
},
|
},
|
||||||
TIMEOUT,
|
TIMEOUT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
'OfferCreate with Deep-Frozen trustline must fail',
|
||||||
|
async () => {
|
||||||
|
assert(wallet_deep_freeze_trustline != null)
|
||||||
|
|
||||||
|
// deep-freeze the trust line
|
||||||
|
const trust_set_tx: TrustSet = {
|
||||||
|
TransactionType: 'TrustSet',
|
||||||
|
Account: testContext.wallet.classicAddress,
|
||||||
|
LimitAmount: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: wallet_deep_freeze_trustline.classicAddress,
|
||||||
|
value: '10',
|
||||||
|
},
|
||||||
|
Flags: {
|
||||||
|
tfSetFreeze: true,
|
||||||
|
tfSetDeepFreeze: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
await testTransaction(
|
||||||
|
testContext.client,
|
||||||
|
trust_set_tx,
|
||||||
|
testContext.wallet,
|
||||||
|
)
|
||||||
|
|
||||||
|
const offer_create_tx: OfferCreate = {
|
||||||
|
TransactionType: 'OfferCreate',
|
||||||
|
Account: testContext.wallet.classicAddress,
|
||||||
|
TakerGets: '13100000',
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: wallet_deep_freeze_trustline.classicAddress,
|
||||||
|
value: '10',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await submitTransaction({
|
||||||
|
client: testContext.client,
|
||||||
|
transaction: offer_create_tx,
|
||||||
|
wallet: testContext.wallet,
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.equal(response.result.engine_result, 'tecFROZEN')
|
||||||
|
},
|
||||||
|
TIMEOUT,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import { stringToHex } from '@xrplf/isomorphic/utils'
|
||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import {
|
||||||
|
LedgerEntryRequest,
|
||||||
|
PermissionedDomainDelete,
|
||||||
|
PermissionedDomainSet,
|
||||||
|
AuthorizeCredential,
|
||||||
|
} from '../../../src'
|
||||||
|
import PermissionedDomain from '../../../src/models/ledger/PermissionedDomain'
|
||||||
|
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('PermissionedDomainSet', function () {
|
||||||
|
let testContext: XrplIntegrationTestContext
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
testContext = await setupClient(serverUrl)
|
||||||
|
})
|
||||||
|
afterEach(async () => teardownClient(testContext))
|
||||||
|
|
||||||
|
it(
|
||||||
|
'Lifecycle of PermissionedDomain ledger object',
|
||||||
|
async () => {
|
||||||
|
const sampleCredential: AuthorizeCredential = {
|
||||||
|
Credential: {
|
||||||
|
CredentialType: stringToHex('Passport'),
|
||||||
|
Issuer: testContext.wallet.classicAddress,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step-1: Test the PermissionedDomainSet transaction
|
||||||
|
const pdSet: PermissionedDomainSet = {
|
||||||
|
TransactionType: 'PermissionedDomainSet',
|
||||||
|
Account: testContext.wallet.classicAddress,
|
||||||
|
AcceptedCredentials: [sampleCredential],
|
||||||
|
}
|
||||||
|
|
||||||
|
await testTransaction(testContext.client, pdSet, testContext.wallet)
|
||||||
|
|
||||||
|
// Step-2: Validate the ledger_entry, account_objects RPC methods
|
||||||
|
// validate the account_objects RPC
|
||||||
|
const result = await testContext.client.request({
|
||||||
|
command: 'account_objects',
|
||||||
|
account: testContext.wallet.classicAddress,
|
||||||
|
type: 'permissioned_domain',
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.equal(result.result.account_objects.length, 1)
|
||||||
|
const pd = result.result.account_objects[0] as PermissionedDomain
|
||||||
|
|
||||||
|
assert.equal(pd.Flags, 0)
|
||||||
|
expect(pd.AcceptedCredentials).toEqual([sampleCredential])
|
||||||
|
|
||||||
|
// validate the ledger_entry RPC
|
||||||
|
const ledgerEntryRequest: LedgerEntryRequest = {
|
||||||
|
command: 'ledger_entry',
|
||||||
|
// fetch the PD `index` from the previous account_objects RPC response
|
||||||
|
index: pd.index,
|
||||||
|
}
|
||||||
|
const ledgerEntryResult = await testContext.client.request(
|
||||||
|
ledgerEntryRequest,
|
||||||
|
)
|
||||||
|
assert.deepEqual(pd, ledgerEntryResult.result.node)
|
||||||
|
|
||||||
|
// Step-3: Test the PDDelete transaction
|
||||||
|
const pdDelete: PermissionedDomainDelete = {
|
||||||
|
TransactionType: 'PermissionedDomainDelete',
|
||||||
|
Account: testContext.wallet.classicAddress,
|
||||||
|
// fetch the PD `index` from the previous account_objects RPC response
|
||||||
|
DomainID: pd.index,
|
||||||
|
}
|
||||||
|
|
||||||
|
await testTransaction(testContext.client, pdDelete, testContext.wallet)
|
||||||
|
},
|
||||||
|
TIMEOUT,
|
||||||
|
)
|
||||||
|
})
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
|
|
||||||
import { TrustSet, percentToQuality, Wallet } from '../../../src'
|
import { TrustSet, percentToQuality, Wallet } from '../../../src'
|
||||||
|
import { RippleState } from '../../../src/models/ledger/index'
|
||||||
|
import { RippleStateFlags } from '../../../src/models/ledger/RippleState'
|
||||||
import serverUrl from '../serverUrl'
|
import serverUrl from '../serverUrl'
|
||||||
import {
|
import {
|
||||||
setupClient,
|
setupClient,
|
||||||
@@ -85,4 +87,60 @@ describe('TrustSet', function () {
|
|||||||
},
|
},
|
||||||
TIMEOUT,
|
TIMEOUT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
'Create a Deep-Frozen trustline',
|
||||||
|
async () => {
|
||||||
|
assert(wallet2 != null)
|
||||||
|
// deep-freeze a trustline with the specified counter-party/currency-code
|
||||||
|
const tx: TrustSet = {
|
||||||
|
TransactionType: 'TrustSet',
|
||||||
|
Account: testContext.wallet.classicAddress,
|
||||||
|
LimitAmount: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: wallet2.classicAddress,
|
||||||
|
value: '10',
|
||||||
|
},
|
||||||
|
Flags: {
|
||||||
|
tfSetFreeze: true,
|
||||||
|
tfSetDeepFreeze: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await testTransaction(
|
||||||
|
testContext.client,
|
||||||
|
tx,
|
||||||
|
testContext.wallet,
|
||||||
|
)
|
||||||
|
assert.equal(response.result.engine_result, 'tesSUCCESS')
|
||||||
|
|
||||||
|
// assert that the trustline is frozen
|
||||||
|
const trustLine = await testContext.client.request({
|
||||||
|
command: 'account_lines',
|
||||||
|
account: testContext.wallet.classicAddress,
|
||||||
|
})
|
||||||
|
assert.equal(trustLine.result.lines[0].freeze, true)
|
||||||
|
|
||||||
|
// verify that the trust-line is deep-frozen
|
||||||
|
// this operation cannot be done with the account_lines RPC
|
||||||
|
const account_objects = await testContext.client.request({
|
||||||
|
command: 'account_objects',
|
||||||
|
account: testContext.wallet.classicAddress,
|
||||||
|
})
|
||||||
|
|
||||||
|
const rippleState = account_objects.result
|
||||||
|
.account_objects[0] as RippleState
|
||||||
|
|
||||||
|
// Depending on the pseudo-random generation of accounts,
|
||||||
|
// either of the below leger-object flags must be set
|
||||||
|
|
||||||
|
const hasDeepFreeze =
|
||||||
|
// eslint-disable-next-line no-bitwise -- required to validate flag
|
||||||
|
(rippleState.Flags & RippleStateFlags.lsfHighDeepFreeze) |
|
||||||
|
// eslint-disable-next-line no-bitwise -- required to validate flag
|
||||||
|
(rippleState.Flags & RippleStateFlags.lsfLowDeepFreeze)
|
||||||
|
assert.isTrue(hasDeepFreeze !== 0)
|
||||||
|
},
|
||||||
|
TIMEOUT,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -373,7 +373,10 @@ export async function getIOUBalance(
|
|||||||
return (await client.request(request)).result.lines[0].balance
|
return (await client.request(request)).result.lines[0].balance
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createAMMPool(client: Client): Promise<{
|
export async function createAMMPool(
|
||||||
|
client: Client,
|
||||||
|
enableAMMClawback = false,
|
||||||
|
): Promise<{
|
||||||
issuerWallet: Wallet
|
issuerWallet: Wallet
|
||||||
lpWallet: Wallet
|
lpWallet: Wallet
|
||||||
asset: Currency
|
asset: Currency
|
||||||
@@ -391,6 +394,16 @@ export async function createAMMPool(client: Client): Promise<{
|
|||||||
|
|
||||||
await testTransaction(client, accountSetTx, issuerWallet)
|
await testTransaction(client, accountSetTx, issuerWallet)
|
||||||
|
|
||||||
|
if (enableAMMClawback) {
|
||||||
|
const accountSetTx2: AccountSet = {
|
||||||
|
TransactionType: 'AccountSet',
|
||||||
|
Account: issuerWallet.classicAddress,
|
||||||
|
SetFlag: AccountSetAsfFlags.asfAllowTrustLineClawback,
|
||||||
|
}
|
||||||
|
|
||||||
|
await testTransaction(client, accountSetTx2, issuerWallet)
|
||||||
|
}
|
||||||
|
|
||||||
const trustSetTx: TrustSet = {
|
const trustSetTx: TrustSet = {
|
||||||
TransactionType: 'TrustSet',
|
TransactionType: 'TrustSet',
|
||||||
Flags: TrustSetFlags.tfClearNoRipple,
|
Flags: TrustSetFlags.tfClearNoRipple,
|
||||||
|
|||||||
176
packages/xrpl/test/models/AMMClawback.test.ts
Normal file
176
packages/xrpl/test/models/AMMClawback.test.ts
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { validate, ValidationError } from '../../src'
|
||||||
|
import {
|
||||||
|
AMMClawbackFlags,
|
||||||
|
validateAMMClawback,
|
||||||
|
} from '../../src/models/transactions/AMMClawback'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AMMClawback Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('AMMClawback', function () {
|
||||||
|
let ammClawback
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
ammClawback = {
|
||||||
|
TransactionType: 'AMMClawback',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
Holder: 'rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9',
|
||||||
|
Asset: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
},
|
||||||
|
Asset2: {
|
||||||
|
currency: 'XRP',
|
||||||
|
},
|
||||||
|
Amount: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
value: '1000',
|
||||||
|
},
|
||||||
|
Sequence: 1337,
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMClawback`, function () {
|
||||||
|
assert.doesNotThrow(() => validateAMMClawback(ammClawback))
|
||||||
|
assert.doesNotThrow(() => validate(ammClawback))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMClawback without Amount`, function () {
|
||||||
|
delete ammClawback.Amount
|
||||||
|
assert.doesNotThrow(() => validateAMMClawback(ammClawback))
|
||||||
|
assert.doesNotThrow(() => validate(ammClawback))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMClawback with tfClawTwoAssets`, function () {
|
||||||
|
ammClawback.flags = AMMClawbackFlags.tfClawTwoAssets
|
||||||
|
assert.doesNotThrow(() => validateAMMClawback(ammClawback))
|
||||||
|
assert.doesNotThrow(() => validate(ammClawback))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing Holder`, function () {
|
||||||
|
delete ammClawback.Holder
|
||||||
|
const errorMessage = 'AMMClawback: missing field Holder'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid field Holder`, function () {
|
||||||
|
ammClawback.Holder = 1234
|
||||||
|
const errorMessage = 'AMMClawback: invalid field Holder'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Holder and Asset.issuer must be distinct`, function () {
|
||||||
|
ammClawback.Holder = ammClawback.Asset.issuer
|
||||||
|
const errorMessage = 'AMMClawback: Holder and Asset.issuer must be distinct'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing Asset`, function () {
|
||||||
|
delete ammClawback.Asset
|
||||||
|
const errorMessage = 'AMMClawback: missing field Asset'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid field Asset`, function () {
|
||||||
|
ammClawback.Asset = '1000'
|
||||||
|
const errorMessage = 'AMMClawback: invalid field Asset'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Account must be the same as Asset.issuer`, function () {
|
||||||
|
ammClawback.Account = 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn'
|
||||||
|
const errorMessage = 'AMMClawback: Account must be the same as Asset.issuer'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing Asset2`, function () {
|
||||||
|
delete ammClawback.Asset2
|
||||||
|
const errorMessage = 'AMMClawback: missing field Asset2'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid field Asset2`, function () {
|
||||||
|
ammClawback.Asset2 = '1000'
|
||||||
|
const errorMessage = 'AMMClawback: invalid field Asset2'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid field Amount`, function () {
|
||||||
|
ammClawback.Amount = 1000
|
||||||
|
const errorMessage = 'AMMClawback: invalid field Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Amount.currency must match Asset.currency`, function () {
|
||||||
|
ammClawback.Amount.currency = 'ETH'
|
||||||
|
const errorMessage =
|
||||||
|
'AMMClawback: Amount.currency must match Asset.currency'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Amount.issuer must match Amount.issuer`, function () {
|
||||||
|
ammClawback.Amount.issuer = 'rnYgaEtpqpNRt3wxE39demVpDAA817rQEY'
|
||||||
|
const errorMessage = 'AMMClawback: Amount.issuer must match Amount.issuer'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMClawback(ammClawback),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammClawback), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
75
packages/xrpl/test/models/NFTokenModify.test.ts
Normal file
75
packages/xrpl/test/models/NFTokenModify.test.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { convertStringToHex, validate, ValidationError } from '../../src'
|
||||||
|
|
||||||
|
const TOKEN_ID =
|
||||||
|
'00090032B5F762798A53D543A014CAF8B297CFF8F2F937E844B17C9E00000003'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NFTokenModify Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('NFTokenModify', function () {
|
||||||
|
it(`verifies valid NFTokenModify`, function () {
|
||||||
|
const validNFTokenModify = {
|
||||||
|
TransactionType: 'NFTokenModify',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
NFTokenID: TOKEN_ID,
|
||||||
|
Fee: '5000000',
|
||||||
|
Sequence: 2470665,
|
||||||
|
URI: convertStringToHex('http://xrpl.org'),
|
||||||
|
} as any
|
||||||
|
|
||||||
|
assert.doesNotThrow(() => validate(validNFTokenModify))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing NFTokenID`, function () {
|
||||||
|
const invalid = {
|
||||||
|
TransactionType: 'NFTokenModify',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
Fee: '5000000',
|
||||||
|
Sequence: 2470665,
|
||||||
|
} as any
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => validate(invalid),
|
||||||
|
ValidationError,
|
||||||
|
'NFTokenModify: missing field NFTokenID',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ URI being an empty string`, function () {
|
||||||
|
const invalid = {
|
||||||
|
TransactionType: 'NFTokenModify',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
NFTokenID: TOKEN_ID,
|
||||||
|
Fee: '5000000',
|
||||||
|
Sequence: 2470665,
|
||||||
|
URI: '',
|
||||||
|
} as any
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => validate(invalid),
|
||||||
|
ValidationError,
|
||||||
|
'NFTokenModify: URI must not be empty string',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ URI not in hex format`, function () {
|
||||||
|
const invalid = {
|
||||||
|
TransactionType: 'NFTokenModify',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
NFTokenID: TOKEN_ID,
|
||||||
|
Fee: '5000000',
|
||||||
|
Sequence: 2470665,
|
||||||
|
URI: '--',
|
||||||
|
} as any
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => validate(invalid),
|
||||||
|
ValidationError,
|
||||||
|
'NFTokenModify: URI must be in hex format',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
49
packages/xrpl/test/models/permissionedDomainDelete.test.ts
Normal file
49
packages/xrpl/test/models/permissionedDomainDelete.test.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { validate, ValidationError } from '../../src'
|
||||||
|
import { validatePermissionedDomainDelete } from '../../src/models/transactions/permissionedDomainDelete'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PermissionedDomainDelete Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('PermissionedDomainDelete', function () {
|
||||||
|
let tx
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
tx = {
|
||||||
|
TransactionType: 'PermissionedDomainDelete',
|
||||||
|
Account: 'rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8',
|
||||||
|
DomainID:
|
||||||
|
'D88930B33C2B6831660BFD006D91FF100011AD4E67CBB78B460AF0A215103737',
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
|
||||||
|
it('verifies valid PermissionedDomainDelete', function () {
|
||||||
|
assert.doesNotThrow(() => validatePermissionedDomainDelete(tx))
|
||||||
|
assert.doesNotThrow(() => validate(tx))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field DomainID`, function () {
|
||||||
|
delete tx.DomainID
|
||||||
|
const errorMessage = 'PermissionedDomainDelete: missing field DomainID'
|
||||||
|
assert.throws(
|
||||||
|
() => validatePermissionedDomainDelete(tx),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid DomainID`, function () {
|
||||||
|
tx.DomainID = 1234
|
||||||
|
const errorMessage = 'PermissionedDomainDelete: invalid field DomainID'
|
||||||
|
assert.throws(
|
||||||
|
() => validatePermissionedDomainDelete(tx),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
92
packages/xrpl/test/models/permissionedDomainSet.test.ts
Normal file
92
packages/xrpl/test/models/permissionedDomainSet.test.ts
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import { stringToHex } from '@xrplf/isomorphic/dist/utils'
|
||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { AuthorizeCredential, validate, ValidationError } from '../../src'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PermissionedDomainSet Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('PermissionedDomainSet', function () {
|
||||||
|
let tx
|
||||||
|
const sampleCredential: AuthorizeCredential = {
|
||||||
|
Credential: {
|
||||||
|
CredentialType: stringToHex('Passport'),
|
||||||
|
Issuer: 'rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
tx = {
|
||||||
|
TransactionType: 'PermissionedDomainSet',
|
||||||
|
Account: 'rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8',
|
||||||
|
DomainID:
|
||||||
|
'D88930B33C2B6831660BFD006D91FF100011AD4E67CBB78B460AF0A215103737',
|
||||||
|
AcceptedCredentials: [sampleCredential],
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
|
||||||
|
it('verifies valid PermissionedDomainSet', function () {
|
||||||
|
assert.doesNotThrow(() => validate(tx))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws with invalid field DomainID`, function () {
|
||||||
|
// DomainID is expected to be a string
|
||||||
|
tx.DomainID = 1234
|
||||||
|
const errorMessage = 'PermissionedDomainSet: invalid field DomainID'
|
||||||
|
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field AcceptedCredentials`, function () {
|
||||||
|
delete tx.AcceptedCredentials
|
||||||
|
const errorMessage =
|
||||||
|
'PermissionedDomainSet: missing field AcceptedCredentials'
|
||||||
|
assert.throws(() => validate(tx), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws when AcceptedCredentials exceeds maximum length', function () {
|
||||||
|
tx.AcceptedCredentials = Array(11).fill(sampleCredential)
|
||||||
|
assert.throws(
|
||||||
|
() => validate(tx),
|
||||||
|
ValidationError,
|
||||||
|
'PermissionedDomainSet: Credentials length cannot exceed 10 elements',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws when AcceptedCredentials is empty', function () {
|
||||||
|
tx.AcceptedCredentials = []
|
||||||
|
assert.throws(
|
||||||
|
() => validate(tx),
|
||||||
|
ValidationError,
|
||||||
|
'PermissionedDomainSet: Credentials cannot be an empty array',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws when AcceptedCredentials is not an array type', function () {
|
||||||
|
tx.AcceptedCredentials = 'AcceptedCredentials is not an array'
|
||||||
|
assert.throws(
|
||||||
|
() => validate(tx),
|
||||||
|
ValidationError,
|
||||||
|
'PermissionedDomainSet: invalid field AcceptedCredentials',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws when AcceptedCredentials contains duplicates', function () {
|
||||||
|
tx.AcceptedCredentials = [sampleCredential, sampleCredential]
|
||||||
|
assert.throws(
|
||||||
|
() => validate(tx),
|
||||||
|
ValidationError,
|
||||||
|
'PermissionedDomainSet: Credentials cannot contain duplicate elements',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws when AcceptedCredentials contains invalid format', function () {
|
||||||
|
tx.AcceptedCredentials = [{ Field1: 'Value1', Field2: 'Value2' }]
|
||||||
|
assert.throws(
|
||||||
|
() => validate(tx),
|
||||||
|
ValidationError,
|
||||||
|
'PermissionedDomainSet: Invalid Credentials format',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -22,6 +22,11 @@ describe('TrustSet', function () {
|
|||||||
},
|
},
|
||||||
QualityIn: 1234,
|
QualityIn: 1234,
|
||||||
QualityOut: 4321,
|
QualityOut: 4321,
|
||||||
|
// an example of deep-frozen trustline
|
||||||
|
Flags: {
|
||||||
|
tfSetFreeze: true,
|
||||||
|
tfSetDeepFreeze: true,
|
||||||
|
},
|
||||||
} as any
|
} as any
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable import/no-deprecated -- using deprecated setTransactionFlagsToNumbers to ensure no breaking changes */
|
||||||
/* eslint-disable no-bitwise -- flags require bitwise operations */
|
/* eslint-disable no-bitwise -- flags require bitwise operations */
|
||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
|
|
||||||
@@ -12,10 +13,13 @@ import {
|
|||||||
TrustSet,
|
TrustSet,
|
||||||
TrustSetFlags,
|
TrustSetFlags,
|
||||||
} from '../../src'
|
} from '../../src'
|
||||||
|
import { AuthorizeCredential } from '../../src/models/common'
|
||||||
import { AccountRootFlags } from '../../src/models/ledger'
|
import { AccountRootFlags } from '../../src/models/ledger'
|
||||||
|
import { containsDuplicates } from '../../src/models/transactions/common'
|
||||||
import { isFlagEnabled } from '../../src/models/utils'
|
import { isFlagEnabled } from '../../src/models/utils'
|
||||||
import {
|
import {
|
||||||
setTransactionFlagsToNumber,
|
setTransactionFlagsToNumber,
|
||||||
|
convertTxFlagsToNumber,
|
||||||
parseAccountRootFlags,
|
parseAccountRootFlags,
|
||||||
parseTransactionFlags,
|
parseTransactionFlags,
|
||||||
} from '../../src/models/utils/flags'
|
} from '../../src/models/utils/flags'
|
||||||
@@ -26,6 +30,43 @@ import {
|
|||||||
* Provides tests for utils used in models.
|
* Provides tests for utils used in models.
|
||||||
*/
|
*/
|
||||||
describe('Models Utils', function () {
|
describe('Models Utils', function () {
|
||||||
|
describe('validate containsDuplicates utility method', function () {
|
||||||
|
it(`use nested-objects for input parameters, list contains duplicates`, function () {
|
||||||
|
// change the order of the inner-objects in the list
|
||||||
|
const list_with_duplicates: AuthorizeCredential[] = [
|
||||||
|
{ Credential: { Issuer: 'alice', CredentialType: 'Passport' } },
|
||||||
|
{ Credential: { CredentialType: 'Passport', Issuer: 'alice' } },
|
||||||
|
]
|
||||||
|
|
||||||
|
assert.isTrue(containsDuplicates(list_with_duplicates))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`use nested-objects for input parameters, no duplicates`, function () {
|
||||||
|
const list_without_dups: AuthorizeCredential[] = [
|
||||||
|
{ Credential: { Issuer: 'alice', CredentialType: 'Passport' } },
|
||||||
|
{ Credential: { CredentialType: 'DMV_license', Issuer: 'bob' } },
|
||||||
|
]
|
||||||
|
|
||||||
|
assert.isFalse(containsDuplicates(list_without_dups))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`use string-IDs for input parameters`, function () {
|
||||||
|
const list_without_dups: string[] = [
|
||||||
|
'EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F66A',
|
||||||
|
'F9F89FBB1426210D58D6A06E5EEF1783D6A90EE403B79AEDF0FED36A6DE238D2',
|
||||||
|
'5328F2D1D6EBBC6093DC10F1EA3DD630666F5B2491EB9BDD7DF9A6C45AC12C46',
|
||||||
|
]
|
||||||
|
|
||||||
|
const list_with_duplicates: string[] = [
|
||||||
|
'EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F66A',
|
||||||
|
'EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F66A',
|
||||||
|
]
|
||||||
|
|
||||||
|
assert.isFalse(containsDuplicates(list_without_dups))
|
||||||
|
assert.isTrue(containsDuplicates(list_with_duplicates))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('isFlagEnabled', function () {
|
describe('isFlagEnabled', function () {
|
||||||
let flags: number
|
let flags: number
|
||||||
const flag1 = 0x00010000
|
const flag1 = 0x00010000
|
||||||
@@ -46,6 +87,65 @@ describe('Models Utils', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('parseAccountRootFlags', function () {
|
||||||
|
// eslint-disable-next-line complexity -- Simpler to list them all out at once.
|
||||||
|
it('all flags enabled', function () {
|
||||||
|
const accountRootFlags =
|
||||||
|
AccountRootFlags.lsfDefaultRipple |
|
||||||
|
AccountRootFlags.lsfDepositAuth |
|
||||||
|
AccountRootFlags.lsfDisableMaster |
|
||||||
|
AccountRootFlags.lsfDisallowXRP |
|
||||||
|
AccountRootFlags.lsfGlobalFreeze |
|
||||||
|
AccountRootFlags.lsfNoFreeze |
|
||||||
|
AccountRootFlags.lsfPasswordSpent |
|
||||||
|
AccountRootFlags.lsfRequireAuth |
|
||||||
|
AccountRootFlags.lsfRequireDestTag |
|
||||||
|
AccountRootFlags.lsfDisallowIncomingNFTokenOffer |
|
||||||
|
AccountRootFlags.lsfDisallowIncomingCheck |
|
||||||
|
AccountRootFlags.lsfDisallowIncomingPayChan |
|
||||||
|
AccountRootFlags.lsfDisallowIncomingTrustline |
|
||||||
|
AccountRootFlags.lsfAllowTrustLineClawback
|
||||||
|
|
||||||
|
const parsed = parseAccountRootFlags(accountRootFlags)
|
||||||
|
|
||||||
|
assert.isTrue(
|
||||||
|
parsed.lsfDefaultRipple &&
|
||||||
|
parsed.lsfDepositAuth &&
|
||||||
|
parsed.lsfDisableMaster &&
|
||||||
|
parsed.lsfDisallowXRP &&
|
||||||
|
parsed.lsfGlobalFreeze &&
|
||||||
|
parsed.lsfNoFreeze &&
|
||||||
|
parsed.lsfPasswordSpent &&
|
||||||
|
parsed.lsfRequireAuth &&
|
||||||
|
parsed.lsfRequireDestTag &&
|
||||||
|
parsed.lsfDisallowIncomingNFTokenOffer &&
|
||||||
|
parsed.lsfDisallowIncomingCheck &&
|
||||||
|
parsed.lsfDisallowIncomingPayChan &&
|
||||||
|
parsed.lsfDisallowIncomingTrustline &&
|
||||||
|
parsed.lsfAllowTrustLineClawback,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('no flags set', function () {
|
||||||
|
const parsed = parseAccountRootFlags(0)
|
||||||
|
|
||||||
|
assert.isUndefined(parsed.lsfDefaultRipple)
|
||||||
|
assert.isUndefined(parsed.lsfDepositAuth)
|
||||||
|
assert.isUndefined(parsed.lsfDisableMaster)
|
||||||
|
assert.isUndefined(parsed.lsfDisallowXRP)
|
||||||
|
assert.isUndefined(parsed.lsfGlobalFreeze)
|
||||||
|
assert.isUndefined(parsed.lsfNoFreeze)
|
||||||
|
assert.isUndefined(parsed.lsfPasswordSpent)
|
||||||
|
assert.isUndefined(parsed.lsfRequireAuth)
|
||||||
|
assert.isUndefined(parsed.lsfRequireDestTag)
|
||||||
|
assert.isUndefined(parsed.lsfDisallowIncomingNFTokenOffer)
|
||||||
|
assert.isUndefined(parsed.lsfDisallowIncomingCheck)
|
||||||
|
assert.isUndefined(parsed.lsfDisallowIncomingPayChan)
|
||||||
|
assert.isUndefined(parsed.lsfDisallowIncomingTrustline)
|
||||||
|
assert.isUndefined(parsed.lsfAllowTrustLineClawback)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('setTransactionFlagsToNumber', function () {
|
describe('setTransactionFlagsToNumber', function () {
|
||||||
it('sets OfferCreateFlags to its numeric value', function () {
|
it('sets OfferCreateFlags to its numeric value', function () {
|
||||||
const tx: OfferCreate = {
|
const tx: OfferCreate = {
|
||||||
@@ -151,64 +251,9 @@ describe('Models Utils', function () {
|
|||||||
setTransactionFlagsToNumber(tx)
|
setTransactionFlagsToNumber(tx)
|
||||||
assert.strictEqual(tx.Flags, 0)
|
assert.strictEqual(tx.Flags, 0)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
// eslint-disable-next-line complexity -- Simpler to list them all out at once.
|
describe('parseTransactionFlags', function () {
|
||||||
it('parseAccountRootFlags all enabled', function () {
|
|
||||||
const accountRootFlags =
|
|
||||||
AccountRootFlags.lsfDefaultRipple |
|
|
||||||
AccountRootFlags.lsfDepositAuth |
|
|
||||||
AccountRootFlags.lsfDisableMaster |
|
|
||||||
AccountRootFlags.lsfDisallowXRP |
|
|
||||||
AccountRootFlags.lsfGlobalFreeze |
|
|
||||||
AccountRootFlags.lsfNoFreeze |
|
|
||||||
AccountRootFlags.lsfPasswordSpent |
|
|
||||||
AccountRootFlags.lsfRequireAuth |
|
|
||||||
AccountRootFlags.lsfRequireDestTag |
|
|
||||||
AccountRootFlags.lsfDisallowIncomingNFTokenOffer |
|
|
||||||
AccountRootFlags.lsfDisallowIncomingCheck |
|
|
||||||
AccountRootFlags.lsfDisallowIncomingPayChan |
|
|
||||||
AccountRootFlags.lsfDisallowIncomingTrustline |
|
|
||||||
AccountRootFlags.lsfAllowTrustLineClawback
|
|
||||||
|
|
||||||
const parsed = parseAccountRootFlags(accountRootFlags)
|
|
||||||
|
|
||||||
assert.isTrue(
|
|
||||||
parsed.lsfDefaultRipple &&
|
|
||||||
parsed.lsfDepositAuth &&
|
|
||||||
parsed.lsfDisableMaster &&
|
|
||||||
parsed.lsfDisallowXRP &&
|
|
||||||
parsed.lsfGlobalFreeze &&
|
|
||||||
parsed.lsfNoFreeze &&
|
|
||||||
parsed.lsfPasswordSpent &&
|
|
||||||
parsed.lsfRequireAuth &&
|
|
||||||
parsed.lsfRequireDestTag &&
|
|
||||||
parsed.lsfDisallowIncomingNFTokenOffer &&
|
|
||||||
parsed.lsfDisallowIncomingCheck &&
|
|
||||||
parsed.lsfDisallowIncomingPayChan &&
|
|
||||||
parsed.lsfDisallowIncomingTrustline &&
|
|
||||||
parsed.lsfAllowTrustLineClawback,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('parseAccountFlags all false', function () {
|
|
||||||
const parsed = parseAccountRootFlags(0)
|
|
||||||
|
|
||||||
assert.isUndefined(parsed.lsfDefaultRipple)
|
|
||||||
assert.isUndefined(parsed.lsfDepositAuth)
|
|
||||||
assert.isUndefined(parsed.lsfDisableMaster)
|
|
||||||
assert.isUndefined(parsed.lsfDisallowXRP)
|
|
||||||
assert.isUndefined(parsed.lsfGlobalFreeze)
|
|
||||||
assert.isUndefined(parsed.lsfNoFreeze)
|
|
||||||
assert.isUndefined(parsed.lsfPasswordSpent)
|
|
||||||
assert.isUndefined(parsed.lsfRequireAuth)
|
|
||||||
assert.isUndefined(parsed.lsfRequireDestTag)
|
|
||||||
assert.isUndefined(parsed.lsfDisallowIncomingNFTokenOffer)
|
|
||||||
assert.isUndefined(parsed.lsfDisallowIncomingCheck)
|
|
||||||
assert.isUndefined(parsed.lsfDisallowIncomingPayChan)
|
|
||||||
assert.isUndefined(parsed.lsfDisallowIncomingTrustline)
|
|
||||||
assert.isUndefined(parsed.lsfAllowTrustLineClawback)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('parseTransactionFlags all enabled', function () {
|
it('parseTransactionFlags all enabled', function () {
|
||||||
const tx: PaymentChannelClaim = {
|
const tx: PaymentChannelClaim = {
|
||||||
Account: 'r...',
|
Account: 'r...',
|
||||||
@@ -264,4 +309,111 @@ describe('Models Utils', function () {
|
|||||||
assert.notStrictEqual(flagsMap, expected)
|
assert.notStrictEqual(flagsMap, expected)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('convertTxFlagsToNumber', function () {
|
||||||
|
it('converts OfferCreateFlags to its numeric value', function () {
|
||||||
|
const tx: OfferCreate = {
|
||||||
|
Account: 'r3rhWeE31Jt5sWmi4QiGLMZnY3ENgqw96W',
|
||||||
|
Fee: '10',
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'DSH',
|
||||||
|
issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX',
|
||||||
|
value: '43.11584856965009',
|
||||||
|
},
|
||||||
|
TakerPays: '12928290425',
|
||||||
|
TransactionType: 'OfferCreate',
|
||||||
|
TxnSignature:
|
||||||
|
'3045022100D874CDDD6BB24ED66E83B1D3574D3ECAC753A78F26DB7EBA89EAB8E7D72B95F802207C8CCD6CEA64E4AE2014E59EE9654E02CA8F03FE7FCE0539E958EAE182234D91',
|
||||||
|
Flags: {
|
||||||
|
tfPassive: true,
|
||||||
|
tfImmediateOrCancel: false,
|
||||||
|
tfFillOrKill: true,
|
||||||
|
tfSell: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tfPassive, tfFillOrKill } = OfferCreateFlags
|
||||||
|
const expected: number = tfPassive | tfFillOrKill
|
||||||
|
|
||||||
|
const result = convertTxFlagsToNumber(tx)
|
||||||
|
assert.strictEqual(result, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('converts PaymentChannelClaimFlags to its numeric value', function () {
|
||||||
|
const tx: PaymentChannelClaim = {
|
||||||
|
Account: 'r...',
|
||||||
|
TransactionType: 'PaymentChannelClaim',
|
||||||
|
Channel:
|
||||||
|
'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198',
|
||||||
|
Flags: {
|
||||||
|
tfRenew: true,
|
||||||
|
tfClose: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tfRenew } = PaymentChannelClaimFlags
|
||||||
|
const expected: number = tfRenew
|
||||||
|
|
||||||
|
const result = convertTxFlagsToNumber(tx)
|
||||||
|
assert.strictEqual(result, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('converts PaymentTransactionFlags to its numeric value', function () {
|
||||||
|
const tx: Payment = {
|
||||||
|
TransactionType: 'Payment',
|
||||||
|
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||||
|
Amount: '1234',
|
||||||
|
Destination: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy',
|
||||||
|
Flags: {
|
||||||
|
tfNoRippleDirect: false,
|
||||||
|
tfPartialPayment: true,
|
||||||
|
tfLimitQuality: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tfPartialPayment, tfLimitQuality } = PaymentFlags
|
||||||
|
const expected: number = tfPartialPayment | tfLimitQuality
|
||||||
|
|
||||||
|
const result = convertTxFlagsToNumber(tx)
|
||||||
|
assert.strictEqual(result, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('converts TrustSetFlags to its numeric value', function () {
|
||||||
|
const tx: TrustSet = {
|
||||||
|
TransactionType: 'TrustSet',
|
||||||
|
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||||
|
LimitAmount: {
|
||||||
|
currency: 'XRP',
|
||||||
|
issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX',
|
||||||
|
value: '4329.23',
|
||||||
|
},
|
||||||
|
QualityIn: 1234,
|
||||||
|
QualityOut: 4321,
|
||||||
|
Flags: {
|
||||||
|
tfSetfAuth: true,
|
||||||
|
tfSetNoRipple: false,
|
||||||
|
tfClearNoRipple: true,
|
||||||
|
tfSetFreeze: false,
|
||||||
|
tfClearFreeze: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tfSetfAuth, tfClearNoRipple, tfClearFreeze } = TrustSetFlags
|
||||||
|
const expected: number = tfSetfAuth | tfClearNoRipple | tfClearFreeze
|
||||||
|
|
||||||
|
const result = convertTxFlagsToNumber(tx)
|
||||||
|
assert.strictEqual(result, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('converts other transaction types flags to its numeric value', function () {
|
||||||
|
const tx: DepositPreauth = {
|
||||||
|
TransactionType: 'DepositPreauth',
|
||||||
|
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||||
|
Flags: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = convertTxFlagsToNumber(tx)
|
||||||
|
assert.strictEqual(result, 0)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user