diff --git a/.vscode/settings.json b/.vscode/settings.json index 2db3c7df59..3bbad24311 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,12 +12,14 @@ "multisign", "multisigned", "multisigning", - "Permissioned", + "nftoken", + "permissioned", "preauthorization", "rippletest", "secp256k1", "Setf", "Sidechains", + "Trustlines", "xchain", "xrplf" ], diff --git a/packages/ripple-binary-codec/src/types/st-array.ts b/packages/ripple-binary-codec/src/types/st-array.ts index c705d4d864..684a69ea03 100644 --- a/packages/ripple-binary-codec/src/types/st-array.ts +++ b/packages/ripple-binary-codec/src/types/st-array.ts @@ -17,6 +17,7 @@ function isObjects(args): args is Array { Array.isArray(args) && args.every( (arg) => + arg != null && typeof arg === 'object' && Object.keys(arg).length === 1 && typeof Object.values(arg)[0] === 'object', diff --git a/packages/xrpl/HISTORY.md b/packages/xrpl/HISTORY.md index ba53ba2a56..e46958fb33 100644 --- a/packages/xrpl/HISTORY.md +++ b/packages/xrpl/HISTORY.md @@ -4,6 +4,9 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr ## Unreleased +### Fixed +* Better error handling and cleaner error messages in model validation + ## 4.6.0 (2026-02-12) ### Added diff --git a/packages/xrpl/src/models/common/index.ts b/packages/xrpl/src/models/common/index.ts index 4297f47252..7c22336afb 100644 --- a/packages/xrpl/src/models/common/index.ts +++ b/packages/xrpl/src/models/common/index.ts @@ -20,6 +20,8 @@ export interface MPTCurrency { export type Currency = IssuedCurrency | MPTCurrency | XRP +export type XRPAmount = string + export interface IssuedCurrencyAmount extends IssuedCurrency { value: string } @@ -30,7 +32,7 @@ export interface MPTAmount { } // TODO: add MPTAmount to Amount once MPTv2 is released -export type Amount = IssuedCurrencyAmount | string +export type Amount = IssuedCurrencyAmount | XRPAmount export type ClawbackAmount = IssuedCurrencyAmount | MPTAmount diff --git a/packages/xrpl/src/models/transactions/AMMBid.ts b/packages/xrpl/src/models/transactions/AMMBid.ts index c8930e72df..4f6aef283a 100644 --- a/packages/xrpl/src/models/transactions/AMMBid.ts +++ b/packages/xrpl/src/models/transactions/AMMBid.ts @@ -2,12 +2,16 @@ import { ValidationError } from '../../errors' import { AuthAccount, Currency, IssuedCurrencyAmount } from '../common' import { + Account, BaseTransaction, + isAccount, isAmount, isArray, - isIssuedCurrency, + isCurrency, isRecord, validateBaseTransaction, + validateOptionalField, + validateRequiredField, } from './common' const MAX_AUTH_ACCOUNTS = 4 @@ -63,29 +67,10 @@ export interface AMMBid extends BaseTransaction { export function validateAMMBid(tx: Record): void { validateBaseTransaction(tx) - if (tx.Asset == null) { - throw new ValidationError('AMMBid: missing field Asset') - } - - if (!isIssuedCurrency(tx.Asset)) { - throw new ValidationError('AMMBid: Asset must be a Currency') - } - - if (tx.Asset2 == null) { - throw new ValidationError('AMMBid: missing field Asset2') - } - - if (!isIssuedCurrency(tx.Asset2)) { - throw new ValidationError('AMMBid: Asset2 must be a Currency') - } - - if (tx.BidMin != null && !isAmount(tx.BidMin)) { - throw new ValidationError('AMMBid: BidMin must be an Amount') - } - - if (tx.BidMax != null && !isAmount(tx.BidMax)) { - throw new ValidationError('AMMBid: BidMax must be an Amount') - } + validateRequiredField(tx, 'Asset', isCurrency) + validateRequiredField(tx, 'Asset2', isCurrency) + validateOptionalField(tx, 'BidMin', isAmount) + validateOptionalField(tx, 'BidMax', isAmount) if (tx.AuthAccounts != null) { if (!isArray(tx.AuthAccounts)) { @@ -103,28 +88,32 @@ export function validateAMMBid(tx: Record): void { } function validateAuthAccounts( - senderAddress: string, + senderAddress: Account, authAccounts: unknown[], ): boolean { - for (const authAccount of authAccounts) { + authAccounts.forEach((authAccount, index) => { if (!isRecord(authAccount)) { - throw new ValidationError(`AMMBid: invalid AuthAccounts`) + throw new ValidationError( + `AMMBid: invalid field AuthAccounts[0], expected a valid Record`, + ) } + const paramName = `AuthAccounts[${index}].AuthAccount` if (!isRecord(authAccount.AuthAccount)) { - throw new ValidationError(`AMMBid: invalid AuthAccounts`) - } - if (authAccount.AuthAccount.Account == null) { - throw new ValidationError(`AMMBid: invalid AuthAccounts`) - } - if (typeof authAccount.AuthAccount.Account !== 'string') { - throw new ValidationError(`AMMBid: invalid AuthAccounts`) + throw new ValidationError( + `AMMBid: invalid field ${paramName}, expected a valid Record`, + ) } + const authAccountInner = authAccount.AuthAccount + validateRequiredField(authAccountInner, 'Account', isAccount, { + paramName, + txType: 'AMMBid', + }) if (authAccount.AuthAccount.Account === senderAddress) { throw new ValidationError( `AMMBid: AuthAccounts must not include sender's address`, ) } - } + }) return true } diff --git a/packages/xrpl/src/models/transactions/AMMClawback.ts b/packages/xrpl/src/models/transactions/AMMClawback.ts index 4afc6ecb4b..5995af3546 100644 --- a/packages/xrpl/src/models/transactions/AMMClawback.ts +++ b/packages/xrpl/src/models/transactions/AMMClawback.ts @@ -6,6 +6,7 @@ import { BaseTransaction, GlobalFlagsInterface, isAccount, + isCurrency, isIssuedCurrency, isIssuedCurrencyAmount, validateBaseTransaction, @@ -97,7 +98,7 @@ export function validateAMMClawback(tx: Record): void { ) } - validateRequiredField(tx, 'Asset2', isIssuedCurrency) + validateRequiredField(tx, 'Asset2', isCurrency) validateOptionalField(tx, 'Amount', isIssuedCurrencyAmount) diff --git a/packages/xrpl/src/models/transactions/AMMCreate.ts b/packages/xrpl/src/models/transactions/AMMCreate.ts index 8924fa75ff..e1e3bbdc4a 100644 --- a/packages/xrpl/src/models/transactions/AMMCreate.ts +++ b/packages/xrpl/src/models/transactions/AMMCreate.ts @@ -1,7 +1,12 @@ -import { ValidationError } from '../../errors' import { Amount } from '../common' -import { BaseTransaction, isAmount, validateBaseTransaction } from './common' +import { + BaseTransaction, + isAmount, + isNumberWithBounds, + validateBaseTransaction, + validateRequiredField, +} from './common' export const AMM_MAX_TRADING_FEE = 1000 @@ -48,33 +53,11 @@ export interface AMMCreate extends BaseTransaction { export function validateAMMCreate(tx: Record): void { validateBaseTransaction(tx) - if (tx.Amount == null) { - throw new ValidationError('AMMCreate: missing field Amount') - } - - if (!isAmount(tx.Amount)) { - throw new ValidationError('AMMCreate: Amount must be an Amount') - } - - if (tx.Amount2 == null) { - throw new ValidationError('AMMCreate: missing field Amount2') - } - - if (!isAmount(tx.Amount2)) { - throw new ValidationError('AMMCreate: Amount2 must be an Amount') - } - - if (tx.TradingFee == null) { - throw new ValidationError('AMMCreate: missing field TradingFee') - } - - if (typeof tx.TradingFee !== 'number') { - throw new ValidationError('AMMCreate: TradingFee must be a number') - } - - if (tx.TradingFee < 0 || tx.TradingFee > AMM_MAX_TRADING_FEE) { - throw new ValidationError( - `AMMCreate: TradingFee must be between 0 and ${AMM_MAX_TRADING_FEE}`, - ) - } + validateRequiredField(tx, 'Amount', isAmount) + validateRequiredField(tx, 'Amount2', isAmount) + validateRequiredField( + tx, + 'TradingFee', + isNumberWithBounds(0, AMM_MAX_TRADING_FEE), + ) } diff --git a/packages/xrpl/src/models/transactions/AMMDelete.ts b/packages/xrpl/src/models/transactions/AMMDelete.ts index b6d96c5126..d6bf2ebc23 100644 --- a/packages/xrpl/src/models/transactions/AMMDelete.ts +++ b/packages/xrpl/src/models/transactions/AMMDelete.ts @@ -1,10 +1,10 @@ -import { ValidationError } from '../../errors' import { Currency } from '../common' import { BaseTransaction, - isIssuedCurrency, + isCurrency, validateBaseTransaction, + validateRequiredField, } from './common' /** @@ -41,19 +41,6 @@ export interface AMMDelete extends BaseTransaction { export function validateAMMDelete(tx: Record): void { validateBaseTransaction(tx) - if (tx.Asset == null) { - throw new ValidationError('AMMDelete: missing field Asset') - } - - if (!isIssuedCurrency(tx.Asset)) { - throw new ValidationError('AMMDelete: Asset must be a Currency') - } - - if (tx.Asset2 == null) { - throw new ValidationError('AMMDelete: missing field Asset2') - } - - if (!isIssuedCurrency(tx.Asset2)) { - throw new ValidationError('AMMDelete: Asset2 must be a Currency') - } + validateRequiredField(tx, 'Asset', isCurrency) + validateRequiredField(tx, 'Asset2', isCurrency) } diff --git a/packages/xrpl/src/models/transactions/AMMDeposit.ts b/packages/xrpl/src/models/transactions/AMMDeposit.ts index cd4c66e23d..d45f98299e 100644 --- a/packages/xrpl/src/models/transactions/AMMDeposit.ts +++ b/packages/xrpl/src/models/transactions/AMMDeposit.ts @@ -5,9 +5,11 @@ import { BaseTransaction, GlobalFlagsInterface, isAmount, - isIssuedCurrency, + isCurrency, isIssuedCurrencyAmount, validateBaseTransaction, + validateOptionalField, + validateRequiredField, } from './common' /** @@ -85,21 +87,12 @@ export interface AMMDeposit extends BaseTransaction { export function validateAMMDeposit(tx: Record): void { validateBaseTransaction(tx) - if (tx.Asset == null) { - throw new ValidationError('AMMDeposit: missing field Asset') - } - - if (!isIssuedCurrency(tx.Asset)) { - throw new ValidationError('AMMDeposit: Asset must be a Currency') - } - - if (tx.Asset2 == null) { - throw new ValidationError('AMMDeposit: missing field Asset2') - } - - if (!isIssuedCurrency(tx.Asset2)) { - throw new ValidationError('AMMDeposit: Asset2 must be a Currency') - } + validateRequiredField(tx, 'Asset', isCurrency) + validateRequiredField(tx, 'Asset2', isCurrency) + validateOptionalField(tx, 'LPTokenOut', isIssuedCurrencyAmount) + validateOptionalField(tx, 'Amount', isAmount) + validateOptionalField(tx, 'Amount2', isAmount) + validateOptionalField(tx, 'EPrice', isAmount) if (tx.Amount2 != null && tx.Amount == null) { throw new ValidationError('AMMDeposit: must set Amount with Amount2') @@ -110,22 +103,4 @@ export function validateAMMDeposit(tx: Record): void { 'AMMDeposit: must set at least LPTokenOut or Amount', ) } - - if (tx.LPTokenOut != null && !isIssuedCurrencyAmount(tx.LPTokenOut)) { - throw new ValidationError( - 'AMMDeposit: LPTokenOut must be an IssuedCurrencyAmount', - ) - } - - if (tx.Amount != null && !isAmount(tx.Amount)) { - throw new ValidationError('AMMDeposit: Amount must be an Amount') - } - - if (tx.Amount2 != null && !isAmount(tx.Amount2)) { - throw new ValidationError('AMMDeposit: Amount2 must be an Amount') - } - - if (tx.EPrice != null && !isAmount(tx.EPrice)) { - throw new ValidationError('AMMDeposit: EPrice must be an Amount') - } } diff --git a/packages/xrpl/src/models/transactions/AMMVote.ts b/packages/xrpl/src/models/transactions/AMMVote.ts index 9d4fdf7286..faab8184fb 100644 --- a/packages/xrpl/src/models/transactions/AMMVote.ts +++ b/packages/xrpl/src/models/transactions/AMMVote.ts @@ -1,11 +1,13 @@ -import { ValidationError } from '../../errors' import { Currency } from '../common' import { AMM_MAX_TRADING_FEE } from './AMMCreate' import { BaseTransaction, - isIssuedCurrency, + isCurrency, + isNumber, + isNumberWithBounds, validateBaseTransaction, + validateRequiredField, } from './common' /** @@ -43,33 +45,12 @@ export interface AMMVote extends BaseTransaction { export function validateAMMVote(tx: Record): void { validateBaseTransaction(tx) - if (tx.Asset == null) { - throw new ValidationError('AMMVote: missing field Asset') - } - - if (!isIssuedCurrency(tx.Asset)) { - throw new ValidationError('AMMVote: Asset must be a Currency') - } - - if (tx.Asset2 == null) { - throw new ValidationError('AMMVote: missing field Asset2') - } - - if (!isIssuedCurrency(tx.Asset2)) { - throw new ValidationError('AMMVote: Asset2 must be a Currency') - } - - if (tx.TradingFee == null) { - throw new ValidationError('AMMVote: missing field TradingFee') - } - - if (typeof tx.TradingFee !== 'number') { - throw new ValidationError('AMMVote: TradingFee must be a number') - } - - if (tx.TradingFee < 0 || tx.TradingFee > AMM_MAX_TRADING_FEE) { - throw new ValidationError( - `AMMVote: TradingFee must be between 0 and ${AMM_MAX_TRADING_FEE}`, - ) - } + validateRequiredField(tx, 'Asset', isCurrency) + validateRequiredField(tx, 'Asset2', isCurrency) + validateRequiredField(tx, 'TradingFee', isNumber) + validateRequiredField( + tx, + 'TradingFee', + isNumberWithBounds(0, AMM_MAX_TRADING_FEE), + ) } diff --git a/packages/xrpl/src/models/transactions/AMMWithdraw.ts b/packages/xrpl/src/models/transactions/AMMWithdraw.ts index 573c7e57d1..c3c360dd9e 100644 --- a/packages/xrpl/src/models/transactions/AMMWithdraw.ts +++ b/packages/xrpl/src/models/transactions/AMMWithdraw.ts @@ -5,9 +5,11 @@ import { BaseTransaction, GlobalFlagsInterface, isAmount, - isIssuedCurrency, + isCurrency, isIssuedCurrencyAmount, validateBaseTransaction, + validateOptionalField, + validateRequiredField, } from './common' /** @@ -83,21 +85,12 @@ export interface AMMWithdraw extends BaseTransaction { export function validateAMMWithdraw(tx: Record): void { validateBaseTransaction(tx) - if (tx.Asset == null) { - throw new ValidationError('AMMWithdraw: missing field Asset') - } - - if (!isIssuedCurrency(tx.Asset)) { - throw new ValidationError('AMMWithdraw: Asset must be a Currency') - } - - if (tx.Asset2 == null) { - throw new ValidationError('AMMWithdraw: missing field Asset2') - } - - if (!isIssuedCurrency(tx.Asset2)) { - throw new ValidationError('AMMWithdraw: Asset2 must be a Currency') - } + validateRequiredField(tx, 'Asset', isCurrency) + validateRequiredField(tx, 'Asset2', isCurrency) + validateOptionalField(tx, 'Amount', isAmount) + validateOptionalField(tx, 'Amount2', isAmount) + validateOptionalField(tx, 'LPTokenIn', isIssuedCurrencyAmount) + validateOptionalField(tx, 'EPrice', isAmount) if (tx.Amount2 != null && tx.Amount == null) { throw new ValidationError('AMMWithdraw: must set Amount with Amount2') @@ -110,16 +103,4 @@ export function validateAMMWithdraw(tx: Record): void { 'AMMWithdraw: LPTokenIn must be an IssuedCurrencyAmount', ) } - - if (tx.Amount != null && !isAmount(tx.Amount)) { - throw new ValidationError('AMMWithdraw: Amount must be an Amount') - } - - if (tx.Amount2 != null && !isAmount(tx.Amount2)) { - throw new ValidationError('AMMWithdraw: Amount2 must be an Amount') - } - - if (tx.EPrice != null && !isAmount(tx.EPrice)) { - throw new ValidationError('AMMWithdraw: EPrice must be an Amount') - } } diff --git a/packages/xrpl/src/models/transactions/DIDDelete.ts b/packages/xrpl/src/models/transactions/DIDDelete.ts index 1cc2a4214d..ea374fda19 100644 --- a/packages/xrpl/src/models/transactions/DIDDelete.ts +++ b/packages/xrpl/src/models/transactions/DIDDelete.ts @@ -1,8 +1,8 @@ import { BaseTransaction, validateBaseTransaction } from './common' -// TODO: add docs - /** + * Delete the DID ledger entry associated with the specified Account field. + * * @category Transaction Models */ export interface DIDDelete extends BaseTransaction { diff --git a/packages/xrpl/src/models/transactions/DIDSet.ts b/packages/xrpl/src/models/transactions/DIDSet.ts index 11416899fd..a9c00dc9a7 100644 --- a/packages/xrpl/src/models/transactions/DIDSet.ts +++ b/packages/xrpl/src/models/transactions/DIDSet.ts @@ -2,14 +2,14 @@ import { ValidationError } from '../../errors' import { BaseTransaction, - isString, + isHexString, validateBaseTransaction, validateOptionalField, } from './common' -// TODO: add docs - /** + * Creates a new DID ledger entry or updates the fields of an existing one. + * * @category Transaction Models */ export interface DIDSet extends BaseTransaction { @@ -31,11 +31,11 @@ export interface DIDSet extends BaseTransaction { export function validateDIDSet(tx: Record): void { validateBaseTransaction(tx) - validateOptionalField(tx, 'Data', isString) + validateOptionalField(tx, 'Data', isHexString) - validateOptionalField(tx, 'DIDDocument', isString) + validateOptionalField(tx, 'DIDDocument', isHexString) - validateOptionalField(tx, 'URI', isString) + validateOptionalField(tx, 'URI', isHexString) if ( tx.Data === undefined && diff --git a/packages/xrpl/src/models/transactions/MPTokenAuthorize.ts b/packages/xrpl/src/models/transactions/MPTokenAuthorize.ts index c796677492..f379cdafc5 100644 --- a/packages/xrpl/src/models/transactions/MPTokenAuthorize.ts +++ b/packages/xrpl/src/models/transactions/MPTokenAuthorize.ts @@ -1,12 +1,12 @@ import { BaseTransaction, - isString, validateBaseTransaction, validateRequiredField, Account, validateOptionalField, isAccount, GlobalFlagsInterface, + isHexString, } from './common' /** @@ -62,6 +62,6 @@ export interface MPTokenAuthorize extends BaseTransaction { */ export function validateMPTokenAuthorize(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'MPTokenIssuanceID', isString) + validateRequiredField(tx, 'MPTokenIssuanceID', isHexString) validateOptionalField(tx, 'Holder', isAccount) } diff --git a/packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts b/packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts index 6a6b6f9e32..eb7c411864 100644 --- a/packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts +++ b/packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts @@ -13,6 +13,7 @@ import { validateOptionalField, isString, isNumber, + isHexString, } from './common' import type { TransactionMetadataBase } from './metadata' @@ -139,10 +140,16 @@ export function validateMPTokenIssuanceCreate( ): void { validateBaseTransaction(tx) validateOptionalField(tx, 'MaximumAmount', isString) - validateOptionalField(tx, 'MPTokenMetadata', isString) + validateOptionalField(tx, 'MPTokenMetadata', isHexString) validateOptionalField(tx, 'TransferFee', isNumber) validateOptionalField(tx, 'AssetScale', isNumber) + if (isHexString(tx.MPTokenMetadata) && tx.MPTokenMetadata === '') { + throw new ValidationError( + 'MPTokenIssuanceCreate: MPTokenMetadata must not be empty string', + ) + } + if ( typeof tx.MPTokenMetadata === 'string' && (!isHex(tx.MPTokenMetadata) || @@ -153,7 +160,7 @@ export function validateMPTokenIssuanceCreate( ) } - if (typeof tx.MaximumAmount === 'string') { + if (isString(tx.MaximumAmount)) { if (!INTEGER_SANITY_CHECK.exec(tx.MaximumAmount)) { throw new ValidationError('MPTokenIssuanceCreate: Invalid MaximumAmount') } else if ( @@ -166,15 +173,12 @@ export function validateMPTokenIssuanceCreate( } } - if (typeof tx.TransferFee === 'number') { + if (isNumber(tx.TransferFee)) { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Not necessary - const flags = (tx.Flags ?? 0) as - | number - | MPTokenIssuanceCreateFlagsInterface - const isTfMPTCanTransfer = - typeof flags === 'number' - ? isFlagEnabled(flags, MPTokenIssuanceCreateFlags.tfMPTCanTransfer) - : (flags.tfMPTCanTransfer ?? false) + const flags = (tx.Flags ?? 0) as number | Record + const isTfMPTCanTransfer = isNumber(flags) + ? isFlagEnabled(flags, MPTokenIssuanceCreateFlags.tfMPTCanTransfer) + : flags.tfMPTCanTransfer === true if (tx.TransferFee < 0 || tx.TransferFee > MAX_TRANSFER_FEE) { throw new ValidationError( diff --git a/packages/xrpl/src/models/transactions/MPTokenIssuanceDestroy.ts b/packages/xrpl/src/models/transactions/MPTokenIssuanceDestroy.ts index 06cbfe9471..98112d1624 100644 --- a/packages/xrpl/src/models/transactions/MPTokenIssuanceDestroy.ts +++ b/packages/xrpl/src/models/transactions/MPTokenIssuanceDestroy.ts @@ -1,6 +1,6 @@ import { BaseTransaction, - isString, + isHexString, validateBaseTransaction, validateRequiredField, } from './common' @@ -30,5 +30,5 @@ export function validateMPTokenIssuanceDestroy( tx: Record, ): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'MPTokenIssuanceID', isString) + validateRequiredField(tx, 'MPTokenIssuanceID', isHexString) } diff --git a/packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts b/packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts index 12d15260ff..3f91bd54c7 100644 --- a/packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts +++ b/packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts @@ -3,13 +3,14 @@ import { isFlagEnabled } from '../utils' import { BaseTransaction, - isString, validateBaseTransaction, validateRequiredField, Account, validateOptionalField, isAccount, GlobalFlagsInterface, + isHexString, + isNumber, } from './common' /** @@ -65,20 +66,18 @@ export interface MPTokenIssuanceSet extends BaseTransaction { */ export function validateMPTokenIssuanceSet(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'MPTokenIssuanceID', isString) + validateRequiredField(tx, 'MPTokenIssuanceID', isHexString) validateOptionalField(tx, 'Holder', isAccount) // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Not necessary - const flags = (tx.Flags ?? 0) as number | MPTokenIssuanceSetFlagsInterface - const isTfMPTLock = - typeof flags === 'number' - ? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTLock) - : (flags.tfMPTLock ?? false) + const flags = (tx.Flags ?? 0) as number | Record + const isTfMPTLock = isNumber(flags) + ? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTLock) + : flags.tfMPTLock === true - const isTfMPTUnlock = - typeof flags === 'number' - ? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTUnlock) - : (flags.tfMPTUnlock ?? false) + const isTfMPTUnlock = isNumber(flags) + ? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTUnlock) + : flags.tfMPTUnlock === true if (isTfMPTLock && isTfMPTUnlock) { throw new ValidationError('MPTokenIssuanceSet: flag conflict') diff --git a/packages/xrpl/src/models/transactions/NFTokenAcceptOffer.ts b/packages/xrpl/src/models/transactions/NFTokenAcceptOffer.ts index 1a33f46e5f..3398bee3b5 100644 --- a/packages/xrpl/src/models/transactions/NFTokenAcceptOffer.ts +++ b/packages/xrpl/src/models/transactions/NFTokenAcceptOffer.ts @@ -3,8 +3,11 @@ import { Amount } from '../common' import { BaseTransaction, + isAmount, + isHexString, parseAmountValue, validateBaseTransaction, + validateOptionalField, } from './common' import type { TransactionMetadataBase } from './metadata' @@ -73,7 +76,10 @@ export interface NFTokenAcceptOfferMetadata extends TransactionMetadataBase { function validateNFTokenBrokerFee(tx: Record): void { const value = parseAmountValue(tx.NFTokenBrokerFee) if (Number.isNaN(value)) { - throw new ValidationError('NFTokenAcceptOffer: invalid NFTokenBrokerFee') + // already checked, additional sanity check + throw new ValidationError( + 'NFTokenAcceptOffer: invalid field NFTokenBrokerFee, expected a valid Amount', + ) } if (value <= 0) { @@ -98,6 +104,10 @@ function validateNFTokenBrokerFee(tx: Record): void { export function validateNFTokenAcceptOffer(tx: Record): void { validateBaseTransaction(tx) + validateOptionalField(tx, 'NFTokenSellOffer', isHexString) + validateOptionalField(tx, 'NFTokenBuyOffer', isHexString) + validateOptionalField(tx, 'NFTokenBrokerFee', isAmount) + if (tx.NFTokenBrokerFee != null) { validateNFTokenBrokerFee(tx) } diff --git a/packages/xrpl/src/models/transactions/NFTokenBurn.ts b/packages/xrpl/src/models/transactions/NFTokenBurn.ts index 00df462459..672c3f4a16 100644 --- a/packages/xrpl/src/models/transactions/NFTokenBurn.ts +++ b/packages/xrpl/src/models/transactions/NFTokenBurn.ts @@ -2,7 +2,7 @@ import { Account, BaseTransaction, isAccount, - isString, + isHexString, validateBaseTransaction, validateOptionalField, validateRequiredField, @@ -47,6 +47,6 @@ export interface NFTokenBurn extends BaseTransaction { */ export function validateNFTokenBurn(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'NFTokenID', isString) + validateRequiredField(tx, 'NFTokenID', isHexString) validateOptionalField(tx, 'Owner', isAccount) } diff --git a/packages/xrpl/src/models/transactions/NFTokenCancelOffer.ts b/packages/xrpl/src/models/transactions/NFTokenCancelOffer.ts index 957fd2b042..66509db218 100644 --- a/packages/xrpl/src/models/transactions/NFTokenCancelOffer.ts +++ b/packages/xrpl/src/models/transactions/NFTokenCancelOffer.ts @@ -1,6 +1,11 @@ import { ValidationError } from '../../errors' -import { BaseTransaction, isArray, validateBaseTransaction } from './common' +import { + BaseTransaction, + isArray, + validateBaseTransaction, + validateRequiredField, +} from './common' import type { TransactionMetadataBase } from './metadata' /** @@ -41,11 +46,9 @@ export interface NFTokenCancelOfferMetadata extends TransactionMetadataBase { export function validateNFTokenCancelOffer(tx: Record): void { validateBaseTransaction(tx) - if (!isArray(tx.NFTokenOffers)) { - throw new ValidationError('NFTokenCancelOffer: missing field NFTokenOffers') - } + validateRequiredField(tx, 'NFTokenOffers', isArray) - if (tx.NFTokenOffers.length < 1) { + if (tx.NFTokenOffers.length === 0) { throw new ValidationError('NFTokenCancelOffer: empty field NFTokenOffers') } } diff --git a/packages/xrpl/src/models/transactions/NFTokenCreateOffer.ts b/packages/xrpl/src/models/transactions/NFTokenCreateOffer.ts index de31645350..dfc09b7e51 100644 --- a/packages/xrpl/src/models/transactions/NFTokenCreateOffer.ts +++ b/packages/xrpl/src/models/transactions/NFTokenCreateOffer.ts @@ -11,6 +11,9 @@ import { isAccount, validateOptionalField, Account, + validateRequiredField, + isNumber, + isHexString, } from './common' import type { TransactionMetadataBase } from './metadata' @@ -135,23 +138,18 @@ export function validateNFTokenCreateOffer(tx: Record): void { ) } - validateOptionalField(tx, 'Destination', isAccount) + validateRequiredField(tx, 'NFTokenID', isHexString) + validateRequiredField(tx, 'Amount', isAmount) validateOptionalField(tx, 'Owner', isAccount) - - if (tx.NFTokenID == null) { - throw new ValidationError('NFTokenCreateOffer: missing field NFTokenID') - } - - if (!isAmount(tx.Amount)) { - throw new ValidationError('NFTokenCreateOffer: invalid Amount') - } + validateOptionalField(tx, 'Expiration', isNumber) + validateOptionalField(tx, 'Destination', isAccount) // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked in BaseTransaction - const flags = (tx.Flags ?? 0) as number | NFTokenCreateOfferFlagsInterface + const flags = (tx.Flags ?? 0) as number | Record const isTfSellNFToken = typeof flags === 'number' ? isFlagEnabled(flags, NFTokenCreateOfferFlags.tfSellNFToken) - : (flags.tfSellNFToken ?? false) + : flags.tfSellNFToken === true if (isTfSellNFToken) { validateNFTokenSellOfferCases(tx) diff --git a/packages/xrpl/src/models/transactions/NFTokenMint.ts b/packages/xrpl/src/models/transactions/NFTokenMint.ts index 56c5a3aee8..695752bf85 100644 --- a/packages/xrpl/src/models/transactions/NFTokenMint.ts +++ b/packages/xrpl/src/models/transactions/NFTokenMint.ts @@ -1,19 +1,23 @@ import { ValidationError } from '../../errors' import { Amount } from '../common' -import { isHex } from '../utils' import { Account, BaseTransaction, GlobalFlagsInterface, isAccount, - isAmount, isNumber, + isHexString, + isAmount, validateBaseTransaction, validateOptionalField, + validateRequiredField, + isNumberWithBounds, } from './common' import type { TransactionMetadataBase } from './metadata' +const MAX_TRANSFER_FEE = 50000 + /** * Transaction Flags for an NFTokenMint Transaction. * @@ -146,26 +150,25 @@ export interface NFTokenMintMetadata extends TransactionMetadataBase { export function validateNFTokenMint(tx: Record): void { validateBaseTransaction(tx) + validateRequiredField(tx, 'NFTokenTaxon', isNumber) + validateOptionalField(tx, 'Issuer', isAccount) + validateOptionalField( + tx, + 'TransferFee', + isNumberWithBounds(0, MAX_TRANSFER_FEE), + ) + validateOptionalField(tx, 'URI', isHexString) + if (tx.Account === tx.Issuer) { throw new ValidationError( 'NFTokenMint: Issuer must not be equal to Account', ) } - validateOptionalField(tx, 'Issuer', isAccount) - if (typeof tx.URI === 'string' && tx.URI === '') { throw new ValidationError('NFTokenMint: URI must not be empty string') } - if (typeof tx.URI === 'string' && !isHex(tx.URI)) { - throw new ValidationError('NFTokenMint: URI must be in hex format') - } - - if (tx.NFTokenTaxon == null) { - throw new ValidationError('NFTokenMint: missing field NFTokenTaxon') - } - if (tx.Amount == null) { if (tx.Expiration != null || tx.Destination != null) { throw new ValidationError( diff --git a/packages/xrpl/src/models/transactions/NFTokenModify.ts b/packages/xrpl/src/models/transactions/NFTokenModify.ts index 4246509671..ecdce3af25 100644 --- a/packages/xrpl/src/models/transactions/NFTokenModify.ts +++ b/packages/xrpl/src/models/transactions/NFTokenModify.ts @@ -1,14 +1,13 @@ import { ValidationError } from '../../errors' -import { isHex } from '../utils' import { BaseTransaction, validateBaseTransaction, isAccount, - isString, validateOptionalField, Account, validateRequiredField, + isHexString, } from './common' /** @@ -52,16 +51,13 @@ export interface NFTokenModify extends BaseTransaction { export function validateNFTokenModify(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'NFTokenID', isString) + validateRequiredField(tx, 'NFTokenID', isHexString) validateOptionalField(tx, 'Owner', isAccount) - validateOptionalField(tx, 'URI', isString) + validateOptionalField(tx, 'URI', isHexString) 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') - } } } diff --git a/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts b/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts index 9b4f274e67..239e094bd3 100644 --- a/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts +++ b/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts @@ -5,8 +5,8 @@ import { BaseTransaction, isAccount, isAmount, + isHexString, isNumber, - isString, isXChainBridge, validateBaseTransaction, validateRequiredField, @@ -101,9 +101,9 @@ export function validateXChainAddAccountCreateAttestation( validateRequiredField(tx, 'OtherChainSource', isAccount) - validateRequiredField(tx, 'PublicKey', isString) + validateRequiredField(tx, 'PublicKey', isHexString) - validateRequiredField(tx, 'Signature', isString) + validateRequiredField(tx, 'Signature', isHexString) validateRequiredField(tx, 'SignatureReward', isAmount) @@ -111,12 +111,14 @@ export function validateXChainAddAccountCreateAttestation( tx, 'WasLockingChainSend', (inp: unknown): inp is 0 | 1 => inp === 0 || inp === 1, + { invalidMessage: 'expected 0 or 1' }, ) validateRequiredField( tx, 'XChainAccountCreateCount', - (inp: unknown): inp is number | string => isNumber(inp) || isString(inp), + (inp: unknown): inp is number | string => isNumber(inp) || isHexString(inp), + { invalidMessage: 'expected a valid number or hex string' }, ) validateRequiredField(tx, 'XChainBridge', isXChainBridge) diff --git a/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts b/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts index 4a1eafe04a..b6c17a5db1 100644 --- a/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts +++ b/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts @@ -5,8 +5,8 @@ import { BaseTransaction, isAccount, isAmount, + isHexString, isNumber, - isString, isXChainBridge, validateBaseTransaction, validateOptionalField, @@ -97,14 +97,15 @@ export function validateXChainAddClaimAttestation( validateRequiredField(tx, 'OtherChainSource', isAccount) - validateRequiredField(tx, 'PublicKey', isString) + validateRequiredField(tx, 'PublicKey', isHexString) - validateRequiredField(tx, 'Signature', isString) + validateRequiredField(tx, 'Signature', isHexString) validateRequiredField( tx, 'WasLockingChainSend', (inp: unknown): inp is 0 | 1 => inp === 0 || inp === 1, + { invalidMessage: 'expected 0 or 1' }, ) validateRequiredField(tx, 'XChainBridge', isXChainBridge) @@ -112,6 +113,7 @@ export function validateXChainAddClaimAttestation( validateRequiredField( tx, 'XChainClaimID', - (inp: unknown): inp is number | string => isNumber(inp) || isString(inp), + (inp: unknown): inp is number | string => isNumber(inp) || isHexString(inp), + { invalidMessage: 'expected a valid number or hex string' }, ) } diff --git a/packages/xrpl/src/models/transactions/XChainClaim.ts b/packages/xrpl/src/models/transactions/XChainClaim.ts index 13897e8d5a..474df6974d 100644 --- a/packages/xrpl/src/models/transactions/XChainClaim.ts +++ b/packages/xrpl/src/models/transactions/XChainClaim.ts @@ -5,8 +5,8 @@ import { BaseTransaction, isAccount, isAmount, + isHexString, isNumber, - isString, isXChainBridge, validateBaseTransaction, validateOptionalField, @@ -68,7 +68,8 @@ export function validateXChainClaim(tx: Record): void { validateRequiredField( tx, 'XChainClaimID', - (inp: unknown): inp is number | string => isNumber(inp) || isString(inp), + (inp: unknown): inp is number | string => isNumber(inp) || isHexString(inp), + { invalidMessage: 'expected a valid number or hex string' }, ) validateRequiredField(tx, 'Destination', isAccount) diff --git a/packages/xrpl/src/models/transactions/XChainCommit.ts b/packages/xrpl/src/models/transactions/XChainCommit.ts index d8767eb27d..c5666e7116 100644 --- a/packages/xrpl/src/models/transactions/XChainCommit.ts +++ b/packages/xrpl/src/models/transactions/XChainCommit.ts @@ -5,8 +5,8 @@ import { BaseTransaction, isAccount, isAmount, + isHexString, isNumber, - isString, isXChainBridge, validateBaseTransaction, validateOptionalField, @@ -67,7 +67,8 @@ export function validateXChainCommit(tx: Record): void { validateRequiredField( tx, 'XChainClaimID', - (inp: unknown): inp is number | string => isNumber(inp) || isString(inp), + (inp: unknown): inp is number | string => isNumber(inp) || isHexString(inp), + { invalidMessage: 'expected a valid number or hex string' }, ) validateOptionalField(tx, 'OtherChainDestination', isAccount) diff --git a/packages/xrpl/src/models/transactions/accountSet.ts b/packages/xrpl/src/models/transactions/accountSet.ts index 33678ff1ff..d1801eb7d1 100644 --- a/packages/xrpl/src/models/transactions/accountSet.ts +++ b/packages/xrpl/src/models/transactions/accountSet.ts @@ -5,6 +5,9 @@ import { BaseTransaction, GlobalFlagsInterface, isAccount, + isHexString, + isNumber, + isNumberWithBounds, validateBaseTransaction, validateOptionalField, } from './common' @@ -174,7 +177,6 @@ const MAX_TICK_SIZE = 15 * @param tx - An AccountSet Transaction. * @throws When the AccountSet is Malformed. */ -// eslint-disable-next-line max-lines-per-function -- okay for this method, only a little over export function validateAccountSet(tx: Record): void { validateBaseTransaction(tx) @@ -182,47 +184,35 @@ export function validateAccountSet(tx: Record): void { if (tx.ClearFlag !== undefined) { if (typeof tx.ClearFlag !== 'number') { - throw new ValidationError('AccountSet: invalid ClearFlag') + throw new ValidationError( + 'AccountSet: invalid field ClearFlag, expected a valid number', + ) } if (!Object.values(AccountSetAsfFlags).includes(tx.ClearFlag)) { - throw new ValidationError('AccountSet: invalid ClearFlag') + throw new ValidationError('AccountSet: invalid ClearFlag value') } } - if (tx.Domain !== undefined && typeof tx.Domain !== 'string') { - throw new ValidationError('AccountSet: invalid Domain') - } - - if (tx.EmailHash !== undefined && typeof tx.EmailHash !== 'string') { - throw new ValidationError('AccountSet: invalid EmailHash') - } - - if (tx.MessageKey !== undefined && typeof tx.MessageKey !== 'string') { - throw new ValidationError('AccountSet: invalid MessageKey') - } + validateOptionalField(tx, 'Domain', isHexString) + validateOptionalField(tx, 'EmailHash', isHexString) + validateOptionalField(tx, 'MessageKey', isHexString) if (tx.SetFlag !== undefined) { if (typeof tx.SetFlag !== 'number') { - throw new ValidationError('AccountSet: invalid SetFlag') + throw new ValidationError( + 'AccountSet: invalid field SetFlag, expected a valid number', + ) } if (!Object.values(AccountSetAsfFlags).includes(tx.SetFlag)) { - throw new ValidationError('AccountSet: invalid SetFlag') + throw new ValidationError('AccountSet: invalid SetFlag value') } } - if (tx.TransferRate !== undefined && typeof tx.TransferRate !== 'number') { - throw new ValidationError('AccountSet: invalid TransferRate') - } + validateOptionalField(tx, 'TransferRate', isNumber) - if (tx.TickSize !== undefined) { - if (typeof tx.TickSize !== 'number') { - throw new ValidationError('AccountSet: invalid TickSize') - } - if ( - tx.TickSize !== 0 && - (tx.TickSize < MIN_TICK_SIZE || tx.TickSize > MAX_TICK_SIZE) - ) { - throw new ValidationError('AccountSet: invalid TickSize') - } - } + validateOptionalField( + tx, + 'TickSize', + isNumberWithBounds(MIN_TICK_SIZE, MAX_TICK_SIZE), + ) } diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index e11f4e4422..3674426c4b 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -120,7 +120,7 @@ export function validateBatch(tx: Record): void { tx.RawTransactions.forEach((rawTxObj, index) => { if (!isRecord(rawTxObj)) { throw new ValidationError( - `Batch: RawTransactions[${index}] is not object.`, + `Batch: invalid field RawTransactions[${index}], expected a valid Record`, ) } validateRequiredField(rawTxObj, 'RawTransaction', isRecord, { diff --git a/packages/xrpl/src/models/transactions/checkCancel.ts b/packages/xrpl/src/models/transactions/checkCancel.ts index 6d129a7d20..acca857d23 100644 --- a/packages/xrpl/src/models/transactions/checkCancel.ts +++ b/packages/xrpl/src/models/transactions/checkCancel.ts @@ -1,6 +1,9 @@ -import { ValidationError } from '../../errors' - -import { BaseTransaction, validateBaseTransaction } from './common' +import { + BaseTransaction, + isHexString, + validateBaseTransaction, + validateRequiredField, +} from './common' /** * Cancels an unredeemed Check, removing it from the ledger without sending any @@ -28,7 +31,5 @@ export interface CheckCancel extends BaseTransaction { export function validateCheckCancel(tx: Record): void { validateBaseTransaction(tx) - if (tx.CheckID !== undefined && typeof tx.CheckID !== 'string') { - throw new ValidationError('CheckCancel: invalid CheckID') - } + validateRequiredField(tx, 'CheckID', isHexString) } diff --git a/packages/xrpl/src/models/transactions/checkCash.ts b/packages/xrpl/src/models/transactions/checkCash.ts index 462f1944c6..33d243393e 100644 --- a/packages/xrpl/src/models/transactions/checkCash.ts +++ b/packages/xrpl/src/models/transactions/checkCash.ts @@ -1,7 +1,14 @@ import { ValidationError } from '../../errors' import { Amount } from '../common' -import { BaseTransaction, validateBaseTransaction, isAmount } from './common' +import { + BaseTransaction, + validateBaseTransaction, + isAmount, + validateRequiredField, + validateOptionalField, + isHexString, +} from './common' /** * Attempts to redeem a Check object in the ledger to receive up to the amount @@ -40,6 +47,10 @@ export interface CheckCash extends BaseTransaction { export function validateCheckCash(tx: Record): void { validateBaseTransaction(tx) + validateRequiredField(tx, 'CheckID', isHexString) + validateOptionalField(tx, 'Amount', isAmount) + validateOptionalField(tx, 'DeliverMin', isAmount) + if (tx.Amount == null && tx.DeliverMin == null) { throw new ValidationError( 'CheckCash: must have either Amount or DeliverMin', @@ -51,22 +62,4 @@ export function validateCheckCash(tx: Record): void { 'CheckCash: cannot have both Amount and DeliverMin', ) } - - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Necessary check - if (tx.Amount != null && tx.Amount !== undefined && !isAmount(tx.Amount)) { - throw new ValidationError('CheckCash: invalid Amount') - } - - if ( - tx.DeliverMin != null && - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Necessary check - tx.DeliverMin !== undefined && - !isAmount(tx.DeliverMin) - ) { - throw new ValidationError('CheckCash: invalid DeliverMin') - } - - if (tx.CheckID !== undefined && typeof tx.CheckID !== 'string') { - throw new ValidationError('CheckCash: invalid CheckID') - } } diff --git a/packages/xrpl/src/models/transactions/checkCreate.ts b/packages/xrpl/src/models/transactions/checkCreate.ts index 7e995ce36f..32f9b38a27 100644 --- a/packages/xrpl/src/models/transactions/checkCreate.ts +++ b/packages/xrpl/src/models/transactions/checkCreate.ts @@ -1,15 +1,15 @@ -import { ValidationError } from '../../errors' import { Amount } from '../common' import { BaseTransaction, validateBaseTransaction, - isIssuedCurrencyAmount, isAccount, validateRequiredField, validateOptionalField, isNumber, Account, + isAmount, + isHexString, } from './common' /** @@ -57,22 +57,9 @@ export interface CheckCreate extends BaseTransaction { export function validateCheckCreate(tx: Record): void { validateBaseTransaction(tx) - if (tx.SendMax === undefined) { - throw new ValidationError('CheckCreate: missing field SendMax') - } - + validateRequiredField(tx, 'SendMax', isAmount) validateRequiredField(tx, 'Destination', isAccount) validateOptionalField(tx, 'DestinationTag', isNumber) - - if (typeof tx.SendMax !== 'string' && !isIssuedCurrencyAmount(tx.SendMax)) { - throw new ValidationError('CheckCreate: invalid SendMax') - } - - if (tx.Expiration !== undefined && typeof tx.Expiration !== 'number') { - throw new ValidationError('CheckCreate: invalid Expiration') - } - - if (tx.InvoiceID !== undefined && typeof tx.InvoiceID !== 'string') { - throw new ValidationError('CheckCreate: invalid InvoiceID') - } + validateOptionalField(tx, 'Expiration', isNumber) + validateOptionalField(tx, 'InvoiceID', isHexString) } diff --git a/packages/xrpl/src/models/transactions/clawback.ts b/packages/xrpl/src/models/transactions/clawback.ts index a1fe39537f..428feded46 100644 --- a/packages/xrpl/src/models/transactions/clawback.ts +++ b/packages/xrpl/src/models/transactions/clawback.ts @@ -46,24 +46,27 @@ export function validateClawback(tx: Record): void { validateBaseTransaction(tx) validateRequiredField(tx, 'Amount', isClawbackAmount) validateOptionalField(tx, 'Holder', isAccount) + validateRequiredField(tx, 'Amount', isClawbackAmount) - if (!isIssuedCurrencyAmount(tx.Amount) && !isMPTAmount(tx.Amount)) { - throw new ValidationError('Clawback: invalid Amount') - } - - if (isIssuedCurrencyAmount(tx.Amount) && tx.Account === tx.Amount.issuer) { - throw new ValidationError('Clawback: invalid holder Account') - } - - if (isMPTAmount(tx.Amount) && tx.Account === tx.Holder) { - throw new ValidationError('Clawback: invalid holder Account') - } + if (isIssuedCurrencyAmount(tx.Amount)) { + if (tx.Account === tx.Amount.issuer) { + throw new ValidationError( + 'Clawback: Amount.issuer and Account cannot be the same', + ) + } - if (isIssuedCurrencyAmount(tx.Amount) && tx.Holder) { - throw new ValidationError('Clawback: cannot have Holder for currency') - } + if (tx.Holder) { + throw new ValidationError('Clawback: cannot have Holder for currency') + } + } else if (isMPTAmount(tx.Amount)) { + if (tx.Account === tx.Holder) { + throw new ValidationError( + 'Clawback: Account and Holder cannot be the same', + ) + } - if (isMPTAmount(tx.Amount) && !tx.Holder) { - throw new ValidationError('Clawback: missing Holder') + if (!tx.Holder) { + throw new ValidationError('Clawback: missing field Holder') + } } } diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index 42dfe47cbf..a3510c197c 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -1,5 +1,4 @@ /* eslint-disable max-lines -- common utility file */ -import { HEX_REGEX } from '@xrplf/isomorphic/utils' import { isValidClassicAddress, isValidXAddress } from 'ripple-address-codec' import { TRANSACTION_TYPES } from 'ripple-binary-codec' @@ -12,9 +11,11 @@ import { IssuedCurrency, IssuedCurrencyAmount, MPTAmount, + MPTCurrency, Memo, Signer, XChainBridge, + XRPAmount, } from '../common' import { isHex, onlyHasFields } from '../utils' @@ -37,13 +38,9 @@ function isMemo(obj: unknown): obj is Memo { return false } const size = Object.keys(memo).length - const validData = - memo.MemoData == null || (isString(memo.MemoData) && isHex(memo.MemoData)) - const validFormat = - memo.MemoFormat == null || - (isString(memo.MemoFormat) && isHex(memo.MemoFormat)) - const validType = - memo.MemoType == null || (isString(memo.MemoType) && isHex(memo.MemoType)) + const validData = memo.MemoData == null || isHexString(memo.MemoData) + const validFormat = memo.MemoFormat == null || isHexString(memo.MemoFormat) + const validType = memo.MemoType == null || isHexString(memo.MemoType) return ( size >= 1 && @@ -97,6 +94,16 @@ export function isRecord(value: unknown): value is Record { return value !== null && typeof value === 'object' && !Array.isArray(value) } +/** + * Verify the form and type of an Array at runtime. + * + * @param input - The object to check the form and type of. + * @returns Whether the Array is properly formed. + */ +export function isArray(input: unknown): input is T[] { + return input != null && Array.isArray(input) +} + /** * Verify the form and type of a string at runtime. * @@ -107,14 +114,73 @@ export function isString(str: unknown): str is string { return typeof str === 'string' } +const NON_STANDARD_CURRENCY_LENGTH = 40 + +/** + * Verify the form and type of a Currency string (STCurrency) at runtime. + * + * @param inp - The object to check the form and type of. + * @returns Whether the Currency string is properly formed. + */ +export function isCurrencyString(inp: unknown): inp is string { + return ( + (isString(inp) && /^[A-Z]{3}$/u.test(inp)) || + (isHexString(inp) && inp.length === NON_STANDARD_CURRENCY_LENGTH) + ) +} + +/** + * Verify the form and type of a hex string at runtime. + * + * @param str - The object to check the form and type of. + * @returns Whether the hex string is properly formed. + */ +export function isHexString(str: unknown): str is string { + return typeof str === 'string' && isHex(str) +} + /** - * Verify the form and type of a number at runtime. + * Verify the form and type of a number at runtime. Includes + * numbers in the form of strings (e.g. `"7"`). * * @param num - The object to check the form and type of. * @returns Whether the number is properly formed. */ export function isNumber(num: unknown): num is number { - return typeof num === 'number' + return ( + (typeof num === 'number' && Number.isInteger(num)) || + (typeof num === 'string' && + num.trim() !== '' && + !Number.isNaN(Number(num)) && + Number.isInteger(Number(num))) + ) +} + +/** + * Verify the form and type of a number at runtime, and ensures that the + * number is within the provided bounds. Includes numbers in the form of + * strings (e.g. `"7"`). + * + * @param lower The lower bound (inclusive). + * @param upper The upper bound (inclusive). + * @returns Whether the number is properly formed and within the bounds. + */ +export function isNumberWithBounds( + lower: number, + upper: number, +): (num: unknown) => num is number { + // eslint-disable-next-line func-style -- returning a function + const isNumberWithBoundsInternal = (num: unknown): num is number => + isNumber(num) && Number(num) >= lower && Number(num) <= upper + return isNumberWithBoundsInternal +} + +function isXRPCurrency(input: unknown): input is Currency { + return ( + isRecord(input) && + Object.keys(input).length === XRP_CURRENCY_SIZE && + input.currency === 'XRP' + ) } /** @@ -168,15 +234,21 @@ export function isXRPLNumber(value: unknown): value is XRPLNumber { * @returns Whether the Currency is properly formed. */ export function isCurrency(input: unknown): input is Currency { + return isXRPCurrency(input) || isIssuedCurrency(input) || isMPTCurrency(input) +} + +/** + * Verify the form and type of an IssuedCurrency at runtime. + * + * @param input - The input to check the form and type of. + * @returns Whether the IssuedCurrency is properly formed. + */ +export function isIssuedCurrency(input: unknown): input is IssuedCurrency { return ( isRecord(input) && - ((Object.keys(input).length === ISSUE_CURRENCY_SIZE && - isString(input.issuer) && - isString(input.currency)) || - (Object.keys(input).length === XRP_CURRENCY_SIZE && - input.currency === 'XRP') || - (Object.keys(input).length === MPT_CURRENCY_SIZE && - isString(input.mpt_issuance_id))) + Object.keys(input).length === ISSUE_CURRENCY_SIZE && + isString(input.issuer) && + isString(input.currency) ) } @@ -186,17 +258,24 @@ export function isCurrency(input: unknown): input is Currency { * @param input - The input to check the form and type of. * @returns Whether the IssuedCurrency is properly formed. */ -export function isIssuedCurrency(input: unknown): input is IssuedCurrency { +export function isMPTCurrency(input: unknown): input is MPTCurrency { return ( isRecord(input) && - ((Object.keys(input).length === ISSUE_CURRENCY_SIZE && - isString(input.issuer) && - isString(input.currency)) || - (Object.keys(input).length === XRP_CURRENCY_SIZE && - input.currency === 'XRP')) + Object.keys(input).length === MPT_CURRENCY_SIZE && + isString(input.mpt_issuance_id) ) } +/** + * Verify the form and type of an IssuedCurrencyAmount at runtime. + * + * @param input - The input to check the form and type of. + * @returns Whether the IssuedCurrencyAmount is properly formed. + */ +export function isXRPAmount(input: unknown): input is XRPAmount { + return isString(input) && isNumber(input) +} + /** * Verify the form and type of an IssuedCurrencyAmount at runtime. * @@ -324,21 +403,54 @@ export function isXChainBridge(input: unknown): input is XChainBridge { return ( isRecord(input) && Object.keys(input).length === XCHAIN_BRIDGE_SIZE && - typeof input.LockingChainDoor === 'string' && - isIssuedCurrency(input.LockingChainIssue) && - typeof input.IssuingChainDoor === 'string' && - isIssuedCurrency(input.IssuingChainIssue) + isString(input.LockingChainDoor) && + isCurrency(input.LockingChainIssue) && + isString(input.IssuingChainDoor) && + isCurrency(input.IssuingChainIssue) ) } -/** - * Verify the form and type of an Array at runtime. - * - * @param input - The object to check the form and type of. - * @returns Whether the Array is properly formed. - */ -export function isArray(input: unknown): input is T[] { - return input != null && Array.isArray(input) +const invalidMessagesMap: Record = { + isAccount: 'account address', + isAmount: 'Amount', + isClawbackAmount: 'non-XRP Amount', + isCurrency: 'Currency', + isXRPAmount: 'XRP Amount', + isIssuedCurrency: 'Issued Currency', + isMPTAmount: 'MPT Amount', + isXChainBridge: 'XChainBridge object', + isMemo: 'Memo', + isSigner: 'Signer', + isRecord: 'Record', + isString: 'string', + isHexString: 'hex string', + isNumber: 'number', + isNumberWithBoundsInternal: 'number', + isArray: 'array', + isIssuedCurrencyAmount: 'IOU Amount', + isCurrencyString: 'currency string', + isXRPLNumber: 'XRPLNumber', +} + +// eslint-disable-next-line max-params -- okay for a helper function +function getErrorMessage( + txType: string, + paramName: string, + functionName: string, + invalidMessage?: string, +): string { + let errorMessage = `${txType}: invalid field ${paramName}` + if (invalidMessage == null) { + const invalidMessageFromMap = invalidMessagesMap[functionName] + // console.log(txType, paramName, functionName, invalidMessageFromMap) + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- okay + if (invalidMessageFromMap != null) { + errorMessage += `, expected a valid ${invalidMessageFromMap}` + } + } else { + errorMessage += `, ${invalidMessage}` + } + return errorMessage } /** @@ -381,6 +493,7 @@ export function validateHexMetadata( * @param errorOpts - Extra values to make the error message easier to understand. * @param errorOpts.txType - The transaction type throwing the error. * @param errorOpts.paramName - The name of the parameter in the transaction with the error. + * @param errorOpts.invalidMessage -- optional error message. * @throws ValidationError if the parameter is missing or invalid. */ // eslint-disable-next-line max-params -- helper function @@ -395,6 +508,7 @@ export function validateRequiredField< errorOpts: { txType?: string paramName?: string + invalidMessage?: string } = {}, ): asserts tx is T & { [P in K]: V } { const paramNameStr = errorOpts.paramName ?? param @@ -407,7 +521,12 @@ export function validateRequiredField< if (!checkValidity(tx[param])) { throw new ValidationError( - `${txType}: invalid field ${String(paramNameStr)}`, + getErrorMessage( + String(txType), + String(paramNameStr), + checkValidity.name, + errorOpts.invalidMessage, + ), ) } } @@ -421,6 +540,7 @@ export function validateRequiredField< * @param errorOpts - Extra values to make the error message easier to understand. * @param errorOpts.txType - The transaction type throwing the error. * @param errorOpts.paramName - The name of the parameter in the transaction with the error. + * @param errorOpts.invalidMessage - optional error message. * @throws ValidationError if the parameter is invalid. */ // eslint-disable-next-line max-params -- helper function @@ -435,13 +555,19 @@ export function validateOptionalField< errorOpts: { txType?: string paramName?: string + invalidMessage?: string } = {}, ): asserts tx is T & { [P in K]: V | undefined } { const paramNameStr = errorOpts.paramName ?? param const txType = errorOpts.txType ?? tx.TransactionType if (tx[param] !== undefined && !checkValidity(tx[param])) { throw new ValidationError( - `${txType}: invalid field ${String(paramNameStr)}`, + getErrorMessage( + String(txType), + String(paramNameStr), + checkValidity.name, + errorOpts.invalidMessage, + ), ) } } @@ -553,14 +679,7 @@ export function validateBaseTransaction( 'BaseTransaction: invalid, expected a valid object', ) } - - if (common.TransactionType === undefined) { - throw new ValidationError('BaseTransaction: missing field TransactionType') - } - - if (typeof common.TransactionType !== 'string') { - throw new ValidationError('BaseTransaction: TransactionType not string') - } + validateRequiredField(common, 'TransactionType', isString) if (!TRANSACTION_TYPES.includes(common.TransactionType)) { throw new ValidationError( @@ -568,19 +687,21 @@ export function validateBaseTransaction( ) } - validateRequiredField(common, 'Account', isString) - - validateOptionalField(common, 'Fee', isString) - + validateRequiredField(common, 'Account', isAccount) + validateOptionalField(common, 'Fee', isXRPAmount) validateOptionalField(common, 'Sequence', isNumber) - - validateOptionalField(common, 'AccountTxnID', isString) - + validateOptionalField(common, 'AccountTxnID', isHexString) validateOptionalField(common, 'LastLedgerSequence', isNumber) + validateOptionalField( + common, + 'Flags', + (inp): inp is number | object => isNumber(inp) || isRecord(inp), + { invalidMessage: 'expected a valid number or Flags object' }, + ) const memos = common.Memos if (memos != null && (!isArray(memos) || !memos.every(isMemo))) { - throw new ValidationError('BaseTransaction: invalid Memos') + throw new ValidationError('BaseTransaction: invalid field Memos') } const signers = common.Signers @@ -589,17 +710,13 @@ export function validateBaseTransaction( signers != null && (!isArray(signers) || signers.length === 0 || !signers.every(isSigner)) ) { - throw new ValidationError('BaseTransaction: invalid Signers') + throw new ValidationError('BaseTransaction: invalid field Signers') } validateOptionalField(common, 'SourceTag', isNumber) - - validateOptionalField(common, 'SigningPubKey', isString) - + validateOptionalField(common, 'SigningPubKey', isHexString) validateOptionalField(common, 'TicketSequence', isNumber) - - validateOptionalField(common, 'TxnSignature', isString) - + validateOptionalField(common, 'TxnSignature', isHexString) validateOptionalField(common, 'NetworkID', isNumber) validateOptionalField(common, 'Delegate', isAccount) @@ -637,20 +754,8 @@ export function parseAmountValue(amount: unknown): number { export function validateCredentialType< T extends BaseTransaction & Record, >(tx: T): void { - if (typeof tx.TransactionType !== 'string') { - throw new ValidationError('Invalid TransactionType') - } - if (tx.CredentialType === undefined) { - throw new ValidationError( - `${tx.TransactionType}: missing field CredentialType`, - ) - } + validateRequiredField(tx, 'CredentialType', isHexString) - if (!isString(tx.CredentialType)) { - throw new ValidationError( - `${tx.TransactionType}: CredentialType must be a string`, - ) - } if (tx.CredentialType.length === 0) { throw new ValidationError( `${tx.TransactionType}: CredentialType cannot be an empty string`, @@ -660,12 +765,6 @@ export function validateCredentialType< `${tx.TransactionType}: CredentialType length cannot be > ${MAX_CREDENTIAL_TYPE_LENGTH}`, ) } - - if (!HEX_REGEX.test(tx.CredentialType)) { - throw new ValidationError( - `${tx.TransactionType}: CredentialType must be encoded in hex`, - ) - } } /** @@ -676,6 +775,7 @@ export function validateCredentialType< * @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. + * @param fieldName The name of the field being validated. Defaults to 'CredentialIDs'. * @throws Validation Error if the formatting is incorrect */ // eslint-disable-next-line max-params, max-lines-per-function -- separating logic further will add unnecessary complexity @@ -684,41 +784,42 @@ export function validateCredentialsList( transactionType: string, isStringID: boolean, maxCredentials: number, + fieldName = 'CredentialIDs', ): void { if (credentials == null) { return } if (!isArray(credentials)) { throw new ValidationError( - `${transactionType}: Credentials must be an array`, + `${transactionType}: invalid field ${fieldName}, expected a valid array`, ) } if (credentials.length > maxCredentials) { throw new ValidationError( - `${transactionType}: Credentials length cannot exceed ${maxCredentials} elements`, + `${transactionType}: ${fieldName} length cannot exceed ${maxCredentials} elements`, ) } else if (credentials.length === 0) { throw new ValidationError( - `${transactionType}: Credentials cannot be an empty array`, + `${transactionType}: ${fieldName} cannot be an empty array`, ) } credentials.forEach((credential) => { if (isStringID) { if (!isString(credential)) { throw new ValidationError( - `${transactionType}: Invalid Credentials ID list format`, + `${transactionType}: Invalid ${fieldName} list format`, ) } } else if (!isAuthorizeCredential(credential)) { throw new ValidationError( - `${transactionType}: Invalid Credentials format`, + `${transactionType}: Invalid ${fieldName} format`, ) } }) // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above if (containsDuplicates(credentials as string[] | AuthorizeCredential[])) { throw new ValidationError( - `${transactionType}: Credentials cannot contain duplicate elements`, + `${transactionType}: ${fieldName} cannot contain duplicate elements`, ) } } @@ -726,7 +827,7 @@ export function validateCredentialsList( // Type guard to ensure we're working with AuthorizeCredential[] // Note: This is not a rigorous type-guard. A more thorough solution would be to iterate over the array and check each item. function isAuthorizeCredentialArray( - list: AuthorizeCredential[] | string[], + list: unknown[], ): list is AuthorizeCredential[] { return typeof list[0] !== 'string' } @@ -737,9 +838,7 @@ function isAuthorizeCredentialArray( * @param objectList - Array of objects to check for duplicates * @returns True if duplicates exist, false otherwise */ -export function containsDuplicates( - objectList: AuthorizeCredential[] | string[], -): boolean { +export function containsDuplicates(objectList: unknown[]): boolean { // Case-1: Process a list of string-IDs if (typeof objectList[0] === 'string') { const objSet = new Set(objectList.map((obj) => JSON.stringify(obj))) diff --git a/packages/xrpl/src/models/transactions/CredentialAccept.ts b/packages/xrpl/src/models/transactions/credentialAccept.ts similarity index 91% rename from packages/xrpl/src/models/transactions/CredentialAccept.ts rename to packages/xrpl/src/models/transactions/credentialAccept.ts index cd0906fc71..f3c5d56ffd 100644 --- a/packages/xrpl/src/models/transactions/CredentialAccept.ts +++ b/packages/xrpl/src/models/transactions/credentialAccept.ts @@ -1,6 +1,6 @@ import { BaseTransaction, - isString, + isAccount, validateBaseTransaction, validateCredentialType, validateRequiredField, @@ -36,9 +36,9 @@ export interface CredentialAccept extends BaseTransaction { export function validateCredentialAccept(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'Account', isString) + validateRequiredField(tx, 'Account', isAccount) - validateRequiredField(tx, 'Issuer', isString) + validateRequiredField(tx, 'Issuer', isAccount) validateCredentialType(tx) } diff --git a/packages/xrpl/src/models/transactions/CredentialCreate.ts b/packages/xrpl/src/models/transactions/credentialCreate.ts similarity index 61% rename from packages/xrpl/src/models/transactions/CredentialCreate.ts rename to packages/xrpl/src/models/transactions/credentialCreate.ts index 8c82b7c74c..711385913e 100644 --- a/packages/xrpl/src/models/transactions/CredentialCreate.ts +++ b/packages/xrpl/src/models/transactions/credentialCreate.ts @@ -1,11 +1,10 @@ -import { HEX_REGEX } from '@xrplf/isomorphic/utils' - import { ValidationError } from '../../errors' import { BaseTransaction, + isAccount, + isHexString, isNumber, - isString, validateBaseTransaction, validateCredentialType, validateOptionalField, @@ -47,35 +46,27 @@ export interface CredentialCreate extends BaseTransaction { export function validateCredentialCreate(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'Account', isString) + validateRequiredField(tx, 'Account', isAccount) - validateRequiredField(tx, 'Subject', isString) + validateRequiredField(tx, 'Subject', isAccount) validateCredentialType(tx) validateOptionalField(tx, 'Expiration', isNumber) - validateURI(tx.URI) -} - -function validateURI(URI: unknown): void { - if (URI === undefined) { - return - } - - if (typeof URI !== 'string') { - throw new ValidationError('CredentialCreate: invalid field URI') - } - - if (URI.length === 0) { - throw new ValidationError('CredentialCreate: URI cannot be an empty string') - } else if (URI.length > MAX_URI_LENGTH) { - throw new ValidationError( - `CredentialCreate: URI length must be <= ${MAX_URI_LENGTH}`, - ) - } - - if (!HEX_REGEX.test(URI)) { - throw new ValidationError('CredentialCreate: URI must be encoded in hex') + validateOptionalField(tx, 'URI', isHexString) + + const uriLength = tx.URI?.length + if (uriLength !== undefined) { + if (uriLength === 0) { + throw new ValidationError( + 'CredentialCreate: URI cannot be an empty string', + ) + } + if (uriLength > MAX_URI_LENGTH) { + throw new ValidationError( + `CredentialCreate: URI length must be <= ${MAX_URI_LENGTH}`, + ) + } } } diff --git a/packages/xrpl/src/models/transactions/CredentialDelete.ts b/packages/xrpl/src/models/transactions/credentialDelete.ts similarity index 88% rename from packages/xrpl/src/models/transactions/CredentialDelete.ts rename to packages/xrpl/src/models/transactions/credentialDelete.ts index d1b4ab0244..64e8f82e8c 100644 --- a/packages/xrpl/src/models/transactions/CredentialDelete.ts +++ b/packages/xrpl/src/models/transactions/credentialDelete.ts @@ -2,7 +2,7 @@ import { ValidationError } from '../../errors' import { BaseTransaction, - isString, + isAccount, validateBaseTransaction, validateCredentialType, validateOptionalField, @@ -45,11 +45,11 @@ export function validateCredentialDelete(tx: Record): void { ) } - validateRequiredField(tx, 'Account', isString) + validateRequiredField(tx, 'Account', isAccount) validateCredentialType(tx) - validateOptionalField(tx, 'Subject', isString) + validateOptionalField(tx, 'Subject', isAccount) - validateOptionalField(tx, 'Issuer', isString) + validateOptionalField(tx, 'Issuer', isAccount) } diff --git a/packages/xrpl/src/models/transactions/delegateSet.ts b/packages/xrpl/src/models/transactions/delegateSet.ts index 08d1a9b994..d8951d5a42 100644 --- a/packages/xrpl/src/models/transactions/delegateSet.ts +++ b/packages/xrpl/src/models/transactions/delegateSet.ts @@ -6,6 +6,9 @@ import { validateRequiredField, isAccount, Account, + isArray, + isRecord, + isString, } from './common' const PERMISSIONS_MAX_LENGTH = 10 @@ -53,7 +56,6 @@ export interface DelegateSet extends BaseTransaction { * @param tx - An DelegateSet Transaction. * @throws When the DelegateSet is malformed. */ -// eslint-disable-next-line max-lines-per-function -- necessary for validation export function validateDelegateSet(tx: Record): void { validateBaseTransaction(tx) @@ -65,46 +67,37 @@ export function validateDelegateSet(tx: Record): void { ) } - validateRequiredField(tx, 'Permissions', Array.isArray) - - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- required for validation - const permissions = tx.Permissions as DelegateSet['Permissions'] - if (permissions.length > PERMISSIONS_MAX_LENGTH) { + validateRequiredField(tx, 'Permissions', isArray) + if (tx.Permissions.length > PERMISSIONS_MAX_LENGTH) { throw new ValidationError( `DelegateSet: Permissions array length cannot be greater than ${PERMISSIONS_MAX_LENGTH}.`, ) } const permissionValueSet = new Set() - permissions.forEach((permission: Permission) => { - if ( - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- required for validation - permission == null || - Object.keys(permission).length !== 1 || - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- required for validation - permission.Permission == null || - Object.keys(permission.Permission).length !== 1 - ) { + tx.Permissions.forEach((permission, index) => { + if (!isRecord(permission) || !isRecord(permission.Permission)) { throw new ValidationError( 'DelegateSet: Permissions array element is malformed', ) } - const permissionValue = permission.Permission.PermissionValue - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- required for validation - if (permissionValue == null) { - throw new ValidationError('DelegateSet: PermissionValue must be defined') - } - if (typeof permissionValue !== 'string') { - throw new ValidationError('DelegateSet: PermissionValue must be a string') - } + const permissionInner = permission.Permission + + validateRequiredField(permissionInner, 'PermissionValue', isString, { + paramName: `Permission[${index}].PermissionValue`, + txType: 'DelegateSet', + }) + + const permissionValue = permissionInner.PermissionValue + if (NON_DELEGABLE_TRANSACTIONS.has(permissionValue)) { throw new ValidationError( - `DelegateSet: PermissionValue contains a non-delegatable transaction ${permissionValue}`, + `DelegateSet: PermissionValue contains non-delegable transaction ${permissionValue}`, ) } permissionValueSet.add(permissionValue) }) - if (permissions.length !== permissionValueSet.size) { + if (tx.Permissions.length !== permissionValueSet.size) { throw new ValidationError( 'DelegateSet: Permissions array cannot contain duplicate values', ) diff --git a/packages/xrpl/src/models/transactions/depositPreauth.ts b/packages/xrpl/src/models/transactions/depositPreauth.ts index 2c4a56a46e..aaac09c9c0 100644 --- a/packages/xrpl/src/models/transactions/depositPreauth.ts +++ b/packages/xrpl/src/models/transactions/depositPreauth.ts @@ -6,6 +6,8 @@ import { validateBaseTransaction, validateCredentialsList, MAX_AUTHORIZED_CREDENTIALS, + validateOptionalField, + isAccount, } from './common' /** @@ -47,21 +49,16 @@ export function validateDepositPreauth(tx: Record): void { validateSingleAuthorizationFieldProvided(tx) - if (tx.Authorize !== undefined) { - if (typeof tx.Authorize !== 'string') { - throw new ValidationError('DepositPreauth: Authorize must be a string') - } + validateOptionalField(tx, 'Authorize', isAccount) + validateOptionalField(tx, 'Unauthorize', isAccount) + if (tx.Authorize !== undefined) { if (tx.Account === tx.Authorize) { throw new ValidationError( "DepositPreauth: Account can't preauthorize its own address", ) } } else if (tx.Unauthorize !== undefined) { - if (typeof tx.Unauthorize !== 'string') { - throw new ValidationError('DepositPreauth: Unauthorize must be a string') - } - if (tx.Account === tx.Unauthorize) { throw new ValidationError( "DepositPreauth: Account can't unauthorize its own address", @@ -73,6 +70,7 @@ export function validateDepositPreauth(tx: Record): void { tx.TransactionType, false, MAX_AUTHORIZED_CREDENTIALS, + 'AuthorizeCredentials', ) } else if (tx.UnauthorizeCredentials !== undefined) { validateCredentialsList( @@ -80,6 +78,7 @@ export function validateDepositPreauth(tx: Record): void { tx.TransactionType, false, MAX_AUTHORIZED_CREDENTIALS, + 'UnauthorizeCredentials', ) } } diff --git a/packages/xrpl/src/models/transactions/escrowCancel.ts b/packages/xrpl/src/models/transactions/escrowCancel.ts index f06676c730..49afec9e7c 100644 --- a/packages/xrpl/src/models/transactions/escrowCancel.ts +++ b/packages/xrpl/src/models/transactions/escrowCancel.ts @@ -1,9 +1,8 @@ -import { ValidationError } from '../../errors' - import { Account, BaseTransaction, isAccount, + isNumber, validateBaseTransaction, validateRequiredField, } from './common' @@ -34,16 +33,5 @@ export function validateEscrowCancel(tx: Record): void { validateBaseTransaction(tx) validateRequiredField(tx, 'Owner', isAccount) - - if (tx.OfferSequence == null) { - throw new ValidationError('EscrowCancel: missing OfferSequence') - } - - if ( - (typeof tx.OfferSequence !== 'number' && - typeof tx.OfferSequence !== 'string') || - Number.isNaN(Number(tx.OfferSequence)) - ) { - throw new ValidationError('EscrowCancel: OfferSequence must be a number') - } + validateRequiredField(tx, 'OfferSequence', isNumber) } diff --git a/packages/xrpl/src/models/transactions/escrowCreate.ts b/packages/xrpl/src/models/transactions/escrowCreate.ts index d779843dcc..15e661ea07 100644 --- a/packages/xrpl/src/models/transactions/escrowCreate.ts +++ b/packages/xrpl/src/models/transactions/escrowCreate.ts @@ -6,6 +6,7 @@ import { BaseTransaction, isAccount, isAmount, + isHexString, isNumber, validateBaseTransaction, validateOptionalField, @@ -64,6 +65,9 @@ export function validateEscrowCreate(tx: Record): void { validateRequiredField(tx, 'Amount', isAmount) validateRequiredField(tx, 'Destination', isAccount) validateOptionalField(tx, 'DestinationTag', isNumber) + validateOptionalField(tx, 'CancelAfter', isNumber) + validateOptionalField(tx, 'FinishAfter', isNumber) + validateOptionalField(tx, 'Condition', isHexString) if (tx.CancelAfter === undefined && tx.FinishAfter === undefined) { throw new ValidationError( @@ -76,16 +80,4 @@ export function validateEscrowCreate(tx: Record): void { 'EscrowCreate: Either Condition or FinishAfter must be specified', ) } - - if (tx.CancelAfter !== undefined && typeof tx.CancelAfter !== 'number') { - throw new ValidationError('EscrowCreate: CancelAfter must be a number') - } - - if (tx.FinishAfter !== undefined && typeof tx.FinishAfter !== 'number') { - throw new ValidationError('EscrowCreate: FinishAfter must be a number') - } - - if (tx.Condition !== undefined && typeof tx.Condition !== 'string') { - throw new ValidationError('EscrowCreate: Condition must be a string') - } } diff --git a/packages/xrpl/src/models/transactions/escrowFinish.ts b/packages/xrpl/src/models/transactions/escrowFinish.ts index fb4a59f963..bcf9729169 100644 --- a/packages/xrpl/src/models/transactions/escrowFinish.ts +++ b/packages/xrpl/src/models/transactions/escrowFinish.ts @@ -1,13 +1,14 @@ -import { ValidationError } from '../../errors' - import { Account, BaseTransaction, isAccount, + isNumber, validateBaseTransaction, validateCredentialsList, + validateOptionalField, validateRequiredField, MAX_AUTHORIZED_CREDENTIALS, + isHexString, } from './common' /** @@ -58,23 +59,7 @@ export function validateEscrowFinish(tx: Record): void { MAX_AUTHORIZED_CREDENTIALS, ) - if (tx.OfferSequence == null) { - throw new ValidationError('EscrowFinish: missing field OfferSequence') - } - - if ( - (typeof tx.OfferSequence !== 'number' && - typeof tx.OfferSequence !== 'string') || - Number.isNaN(Number(tx.OfferSequence)) - ) { - throw new ValidationError('EscrowFinish: OfferSequence must be a number') - } - - if (tx.Condition !== undefined && typeof tx.Condition !== 'string') { - throw new ValidationError('EscrowFinish: Condition must be a string') - } - - if (tx.Fulfillment !== undefined && typeof tx.Fulfillment !== 'string') { - throw new ValidationError('EscrowFinish: Fulfillment must be a string') - } + validateRequiredField(tx, 'OfferSequence', isNumber) + validateOptionalField(tx, 'Condition', isHexString) + validateOptionalField(tx, 'Fulfillment', isHexString) } diff --git a/packages/xrpl/src/models/transactions/index.ts b/packages/xrpl/src/models/transactions/index.ts index d7afb63012..77433b90d2 100644 --- a/packages/xrpl/src/models/transactions/index.ts +++ b/packages/xrpl/src/models/transactions/index.ts @@ -43,9 +43,9 @@ export { CheckCancel } from './checkCancel' export { CheckCash } from './checkCash' export { CheckCreate } from './checkCreate' export { Clawback } from './clawback' -export { CredentialAccept } from './CredentialAccept' -export { CredentialCreate } from './CredentialCreate' -export { CredentialDelete } from './CredentialDelete' +export { CredentialAccept } from './credentialAccept' +export { CredentialCreate } from './credentialCreate' +export { CredentialDelete } from './credentialDelete' export { DIDDelete } from './DIDDelete' export { DIDSet } from './DIDSet' export { DelegateSet, Permission } from './delegateSet' diff --git a/packages/xrpl/src/models/transactions/offerCancel.ts b/packages/xrpl/src/models/transactions/offerCancel.ts index 4989d18883..29e4d48779 100644 --- a/packages/xrpl/src/models/transactions/offerCancel.ts +++ b/packages/xrpl/src/models/transactions/offerCancel.ts @@ -1,6 +1,9 @@ -import { ValidationError } from '../../errors' - -import { BaseTransaction, validateBaseTransaction } from './common' +import { + BaseTransaction, + isNumber, + validateBaseTransaction, + validateRequiredField, +} from './common' /** * An OfferCancel transaction removes an Offer object from the XRP Ledger. @@ -27,11 +30,5 @@ export interface OfferCancel extends BaseTransaction { export function validateOfferCancel(tx: Record): void { validateBaseTransaction(tx) - if (tx.OfferSequence === undefined) { - throw new ValidationError('OfferCancel: missing field OfferSequence') - } - - if (typeof tx.OfferSequence !== 'number') { - throw new ValidationError('OfferCancel: OfferSequence must be a number') - } + validateRequiredField(tx, 'OfferSequence', isNumber) } diff --git a/packages/xrpl/src/models/transactions/offerCreate.ts b/packages/xrpl/src/models/transactions/offerCreate.ts index acdb04e59e..30f6f7a0a1 100644 --- a/packages/xrpl/src/models/transactions/offerCreate.ts +++ b/packages/xrpl/src/models/transactions/offerCreate.ts @@ -7,7 +7,9 @@ import { GlobalFlagsInterface, validateBaseTransaction, isAmount, + validateRequiredField, validateOptionalField, + isNumber, isDomainID, } from './common' @@ -128,29 +130,10 @@ export interface OfferCreate extends BaseTransaction { export function validateOfferCreate(tx: Record): void { validateBaseTransaction(tx) - if (tx.TakerGets === undefined) { - throw new ValidationError('OfferCreate: missing field TakerGets') - } - - if (tx.TakerPays === undefined) { - throw new ValidationError('OfferCreate: missing field TakerPays') - } - - if (typeof tx.TakerGets !== 'string' && !isAmount(tx.TakerGets)) { - throw new ValidationError('OfferCreate: invalid TakerGets') - } - - if (typeof tx.TakerPays !== 'string' && !isAmount(tx.TakerPays)) { - throw new ValidationError('OfferCreate: invalid TakerPays') - } - - if (tx.Expiration !== undefined && typeof tx.Expiration !== 'number') { - throw new ValidationError('OfferCreate: invalid Expiration') - } - - if (tx.OfferSequence !== undefined && typeof tx.OfferSequence !== 'number') { - throw new ValidationError('OfferCreate: invalid OfferSequence') - } + validateOptionalField(tx, 'Expiration', isNumber) + validateOptionalField(tx, 'OfferSequence', isNumber) + validateRequiredField(tx, 'TakerGets', isAmount) + validateRequiredField(tx, 'TakerPays', isAmount) validateOptionalField(tx, 'DomainID', isDomainID, { txType: 'OfferCreate', diff --git a/packages/xrpl/src/models/transactions/oracleSet.ts b/packages/xrpl/src/models/transactions/oracleSet.ts index c28c89e902..853ddc6483 100644 --- a/packages/xrpl/src/models/transactions/oracleSet.ts +++ b/packages/xrpl/src/models/transactions/oracleSet.ts @@ -1,11 +1,13 @@ import { ValidationError } from '../../errors' import { PriceData } from '../common' -import { isHex } from '../utils' import { BaseTransaction, isArray, + isCurrencyString, + isHexString, isNumber, + isNumberWithBounds, isRecord, isString, validateBaseTransaction, @@ -81,13 +83,13 @@ export function validateOracleSet(tx: Record): void { validateRequiredField(tx, 'LastUpdateTime', isNumber) - validateOptionalField(tx, 'Provider', isString) + validateOptionalField(tx, 'Provider', isHexString) - validateOptionalField(tx, 'URI', isString) + validateOptionalField(tx, 'URI', isHexString) - validateOptionalField(tx, 'AssetClass', isString) + validateOptionalField(tx, 'AssetClass', isHexString) - /* eslint-disable max-statements, max-lines-per-function -- necessary to validate many fields */ + /* eslint-disable max-lines-per-function -- necessary to validate many fields */ validateRequiredField( tx, 'PriceDataSeries', @@ -103,16 +105,13 @@ export function validateOracleSet(tx: Record): void { } // TODO: add support for handling inner objects easier (similar to validateRequiredField/validateOptionalField) - for (const priceData of value) { + value.forEach((priceData, index) => { if (!isRecord(priceData)) { throw new ValidationError( 'OracleSet: PriceDataSeries must be an array of objects', ) } - - const priceDataInner = priceData.PriceData - - if (!isRecord(priceDataInner)) { + if (!isRecord(priceData.PriceData)) { throw new ValidationError( 'OracleSet: PriceDataSeries must have a `PriceData` object', ) @@ -125,20 +124,17 @@ export function validateOracleSet(tx: Record): void { ) } - if ( - priceDataInner.BaseAsset == null || - typeof priceDataInner.BaseAsset !== 'string' - ) { - throw new ValidationError( - 'OracleSet: PriceDataSeries must have a `BaseAsset` string', - ) - } + const priceDataInner = priceData.PriceData - if (typeof priceDataInner.QuoteAsset !== 'string') { - throw new ValidationError( - 'OracleSet: PriceDataSeries must have a `QuoteAsset` string', - ) - } + validateRequiredField(priceDataInner, 'BaseAsset', isCurrencyString, { + paramName: `PriceDataSeries[${index}].BaseAsset`, + txType: 'OracleSet', + }) + + validateRequiredField(priceDataInner, 'QuoteAsset', isCurrencyString, { + paramName: `PriceDataSeries[${index}].QuoteAsset`, + txType: 'OracleSet', + }) // Either AssetPrice and Scale are both present or both excluded if ( @@ -150,20 +146,20 @@ export function validateOracleSet(tx: Record): void { ) } - /* eslint-disable max-depth -- - we need to validate priceDataInner.AssetPrice value */ + validateOptionalField( + priceDataInner, + 'AssetPrice', + // eslint-disable-next-line max-nested-callbacks -- okay here + (inp: unknown): inp is number | string => + isNumber(inp) || isHexString(inp), + { + paramName: `PriceDataSeries[${index}].AssetPrice`, + txType: 'OracleSet', + }, + ) + if ('AssetPrice' in priceDataInner) { - if (!isNumber(priceDataInner.AssetPrice)) { - if (typeof priceDataInner.AssetPrice !== 'string') { - throw new ValidationError( - 'OracleSet: Field AssetPrice must be a string or a number', - ) - } - if (!isHex(priceDataInner.AssetPrice)) { - throw new ValidationError( - 'OracleSet: Field AssetPrice must be a valid hex string', - ) - } + if (isString(priceDataInner.AssetPrice)) { if ( priceDataInner.AssetPrice.length < MINIMUM_ASSET_PRICE_LENGTH || priceDataInner.AssetPrice.length > MAXIMUM_ASSET_PRICE_LENGTH @@ -175,21 +171,18 @@ export function validateOracleSet(tx: Record): void { } } - if ('Scale' in priceDataInner) { - if (!isNumber(priceDataInner.Scale)) { - throw new ValidationError('OracleSet: invalid field Scale') - } - - if (priceDataInner.Scale < 0 || priceDataInner.Scale > SCALE_MAX) { - throw new ValidationError( - `OracleSet: Scale must be in range 0-${SCALE_MAX}`, - ) - } - /* eslint-enable max-depth */ - } - } + validateOptionalField( + priceDataInner, + 'Scale', + isNumberWithBounds(0, SCALE_MAX), + { + paramName: `PriceDataSeries[${index}].Scale`, + txType: 'OracleSet', + }, + ) + }) return true }, ) - /* eslint-enable max-statements, max-lines-per-function */ + /* eslint-enable max-lines-per-function */ } diff --git a/packages/xrpl/src/models/transactions/payment.ts b/packages/xrpl/src/models/transactions/payment.ts index cf5ee4f884..51ca213895 100644 --- a/packages/xrpl/src/models/transactions/payment.ts +++ b/packages/xrpl/src/models/transactions/payment.ts @@ -15,6 +15,7 @@ import { Account, validateCredentialsList, MAX_AUTHORIZED_CREDENTIALS, + isHexString, isArray, } from './common' import type { TransactionMetadataBase } from './metadata' @@ -190,16 +191,16 @@ export interface PaymentMetadata extends TransactionMetadataBase { export function validatePayment(tx: Record): void { validateBaseTransaction(tx) - if (tx.Amount === undefined) { - throw new ValidationError('PaymentTransaction: missing field Amount') - } - - if (!isAmount(tx.Amount)) { - throw new ValidationError('PaymentTransaction: invalid Amount') - } - + validateRequiredField(tx, 'Amount', isAmount) validateRequiredField(tx, 'Destination', isAccount) validateOptionalField(tx, 'DestinationTag', isNumber) + validateOptionalField(tx, 'InvoiceID', isHexString) + validateOptionalField(tx, 'Paths', isPaths, { + invalidMessage: 'expected a valid Paths array', + }) + + validateOptionalField(tx, 'SendMax', isAmount) + validateOptionalField(tx, 'DeliverMin', isAmount) validateCredentialsList( tx.CredentialIDs, @@ -207,24 +208,11 @@ export function validatePayment(tx: Record): void { true, MAX_AUTHORIZED_CREDENTIALS, ) - - if (tx.InvoiceID !== undefined && typeof tx.InvoiceID !== 'string') { - throw new ValidationError('PaymentTransaction: InvoiceID must be a string') - } - validateOptionalField(tx, 'DomainID', isDomainID, { txType: 'PaymentTransaction', paramName: 'DomainID', }) - if (tx.Paths !== undefined && !isPaths(tx.Paths)) { - throw new ValidationError('PaymentTransaction: invalid Paths') - } - - if (tx.SendMax !== undefined && !isAmount(tx.SendMax)) { - throw new ValidationError('PaymentTransaction: invalid SendMax') - } - checkPartialPayment(tx) } @@ -232,7 +220,7 @@ function checkPartialPayment(tx: Record): void { if (tx.DeliverMin != null) { if (tx.Flags == null) { throw new ValidationError( - 'PaymentTransaction: tfPartialPayment flag required with DeliverMin', + 'Payment: tfPartialPayment flag required with DeliverMin', ) } @@ -245,12 +233,14 @@ function checkPartialPayment(tx: Record): void { if (!isTfPartialPayment) { throw new ValidationError( - 'PaymentTransaction: tfPartialPayment flag required with DeliverMin', + 'Payment: tfPartialPayment flag required with DeliverMin', ) } if (!isAmount(tx.DeliverMin)) { - throw new ValidationError('PaymentTransaction: invalid DeliverMin') + throw new ValidationError( + 'Payment: invalid field DeliverMin, expected a valid Amount', + ) } } } diff --git a/packages/xrpl/src/models/transactions/paymentChannelClaim.ts b/packages/xrpl/src/models/transactions/paymentChannelClaim.ts index d13f694dbe..2989238a49 100644 --- a/packages/xrpl/src/models/transactions/paymentChannelClaim.ts +++ b/packages/xrpl/src/models/transactions/paymentChannelClaim.ts @@ -1,11 +1,13 @@ -import { ValidationError } from '../../errors' - import { BaseTransaction, GlobalFlagsInterface, validateBaseTransaction, validateCredentialsList, + validateOptionalField, + validateRequiredField, MAX_AUTHORIZED_CREDENTIALS, + isHexString, + isXRPAmount, } from './common' /** @@ -150,34 +152,16 @@ export interface PaymentChannelClaim extends BaseTransaction { export function validatePaymentChannelClaim(tx: Record): void { validateBaseTransaction(tx) + validateRequiredField(tx, 'Channel', isHexString) + validateOptionalField(tx, 'Balance', isXRPAmount) + validateOptionalField(tx, 'Amount', isXRPAmount) + validateOptionalField(tx, 'Signature', isHexString) + validateOptionalField(tx, 'PublicKey', isHexString) + validateCredentialsList( tx.CredentialIDs, tx.TransactionType, true, MAX_AUTHORIZED_CREDENTIALS, ) - - if (tx.Channel === undefined) { - throw new ValidationError('PaymentChannelClaim: missing Channel') - } - - if (typeof tx.Channel !== 'string') { - throw new ValidationError('PaymentChannelClaim: Channel must be a string') - } - - if (tx.Balance !== undefined && typeof tx.Balance !== 'string') { - throw new ValidationError('PaymentChannelClaim: Balance must be a string') - } - - if (tx.Amount !== undefined && typeof tx.Amount !== 'string') { - throw new ValidationError('PaymentChannelClaim: Amount must be a string') - } - - if (tx.Signature !== undefined && typeof tx.Signature !== 'string') { - throw new ValidationError('PaymentChannelClaim: Signature must be a string') - } - - if (tx.PublicKey !== undefined && typeof tx.PublicKey !== 'string') { - throw new ValidationError('PaymentChannelClaim: PublicKey must be a string') - } } diff --git a/packages/xrpl/src/models/transactions/paymentChannelCreate.ts b/packages/xrpl/src/models/transactions/paymentChannelCreate.ts index 1a7ca3eadc..53130905bd 100644 --- a/packages/xrpl/src/models/transactions/paymentChannelCreate.ts +++ b/packages/xrpl/src/models/transactions/paymentChannelCreate.ts @@ -1,10 +1,10 @@ -import { ValidationError } from '../../errors' - import { Account, BaseTransaction, isAccount, + isHexString, isNumber, + isXRPAmount, validateBaseTransaction, validateOptionalField, validateRequiredField, @@ -30,6 +30,11 @@ export interface PaymentChannelCreate extends BaseTransaction { * the "destination address" for the channel. */ Destination: Account + /** + * Arbitrary tag to further specify the destination for this payment channel, + * such as a hosted recipient at the destination address. + */ + DestinationTag?: number /** * Amount of time the source address must wait before closing the channel if * it has unclaimed XRP. @@ -49,11 +54,6 @@ export interface PaymentChannelCreate extends BaseTransaction { * this time. */ CancelAfter?: number - /** - * Arbitrary tag to further specify the destination for this payment channel, - * such as a hosted recipient at the destination address. - */ - DestinationTag?: number } /** @@ -67,40 +67,10 @@ export function validatePaymentChannelCreate( ): void { validateBaseTransaction(tx) - if (tx.Amount === undefined) { - throw new ValidationError('PaymentChannelCreate: missing Amount') - } - - if (typeof tx.Amount !== 'string') { - throw new ValidationError('PaymentChannelCreate: Amount must be a string') - } - + validateRequiredField(tx, 'Amount', isXRPAmount) validateRequiredField(tx, 'Destination', isAccount) validateOptionalField(tx, 'DestinationTag', isNumber) - - if (tx.SettleDelay === undefined) { - throw new ValidationError('PaymentChannelCreate: missing SettleDelay') - } - - if (typeof tx.SettleDelay !== 'number') { - throw new ValidationError( - 'PaymentChannelCreate: SettleDelay must be a number', - ) - } - - if (tx.PublicKey === undefined) { - throw new ValidationError('PaymentChannelCreate: missing PublicKey') - } - - if (typeof tx.PublicKey !== 'string') { - throw new ValidationError( - 'PaymentChannelCreate: PublicKey must be a string', - ) - } - - if (tx.CancelAfter !== undefined && typeof tx.CancelAfter !== 'number') { - throw new ValidationError( - 'PaymentChannelCreate: CancelAfter must be a number', - ) - } + validateRequiredField(tx, 'SettleDelay', isNumber) + validateRequiredField(tx, 'PublicKey', isHexString) + validateOptionalField(tx, 'CancelAfter', isNumber) } diff --git a/packages/xrpl/src/models/transactions/paymentChannelFund.ts b/packages/xrpl/src/models/transactions/paymentChannelFund.ts index 8c46687afa..57064908fc 100644 --- a/packages/xrpl/src/models/transactions/paymentChannelFund.ts +++ b/packages/xrpl/src/models/transactions/paymentChannelFund.ts @@ -1,6 +1,12 @@ -import { ValidationError } from '../../errors' - -import { BaseTransaction, validateBaseTransaction } from './common' +import { + BaseTransaction, + isHexString, + isNumber, + isXRPAmount, + validateBaseTransaction, + validateOptionalField, + validateRequiredField, +} from './common' /** * Add additional XRP to an open payment channel, and optionally update the @@ -43,23 +49,7 @@ export interface PaymentChannelFund extends BaseTransaction { export function validatePaymentChannelFund(tx: Record): void { validateBaseTransaction(tx) - if (tx.Channel === undefined) { - throw new ValidationError('PaymentChannelFund: missing Channel') - } - - if (typeof tx.Channel !== 'string') { - throw new ValidationError('PaymentChannelFund: Channel must be a string') - } - - if (tx.Amount === undefined) { - throw new ValidationError('PaymentChannelFund: missing Amount') - } - - if (typeof tx.Amount !== 'string') { - throw new ValidationError('PaymentChannelFund: Amount must be a string') - } - - if (tx.Expiration !== undefined && typeof tx.Expiration !== 'number') { - throw new ValidationError('PaymentChannelFund: Expiration must be a number') - } + validateRequiredField(tx, 'Channel', isHexString) + validateRequiredField(tx, 'Amount', isXRPAmount) + validateOptionalField(tx, 'Expiration', isNumber) } diff --git a/packages/xrpl/src/models/transactions/permissionedDomainDelete.ts b/packages/xrpl/src/models/transactions/permissionedDomainDelete.ts index 8a2a0db6c8..a96607dfd0 100644 --- a/packages/xrpl/src/models/transactions/permissionedDomainDelete.ts +++ b/packages/xrpl/src/models/transactions/permissionedDomainDelete.ts @@ -1,6 +1,6 @@ import { BaseTransaction, - isString, + isHexString, validateBaseTransaction, validateRequiredField, } from './common' @@ -24,5 +24,5 @@ export function validatePermissionedDomainDelete( ): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'DomainID', isString) + validateRequiredField(tx, 'DomainID', isHexString) } diff --git a/packages/xrpl/src/models/transactions/permissionedDomainSet.ts b/packages/xrpl/src/models/transactions/permissionedDomainSet.ts index 9e6319bb83..518c2d9efe 100644 --- a/packages/xrpl/src/models/transactions/permissionedDomainSet.ts +++ b/packages/xrpl/src/models/transactions/permissionedDomainSet.ts @@ -2,11 +2,11 @@ import { AuthorizeCredential } from '../common' import { BaseTransaction, - isString, validateBaseTransaction, validateOptionalField, validateRequiredField, validateCredentialsList, + isHexString, isArray, } from './common' @@ -36,7 +36,7 @@ export function validatePermissionedDomainSet( ): void { validateBaseTransaction(tx) - validateOptionalField(tx, 'DomainID', isString) + validateOptionalField(tx, 'DomainID', isHexString) validateRequiredField(tx, 'AcceptedCredentials', isArray) validateCredentialsList( @@ -46,5 +46,6 @@ export function validatePermissionedDomainSet( false, // PermissionedDomainSet uses at most 10 accepted credentials. This is different from Credential-feature transactions. MAX_ACCEPTED_CREDENTIALS, + 'AcceptedCredentials', ) } diff --git a/packages/xrpl/src/models/transactions/setRegularKey.ts b/packages/xrpl/src/models/transactions/setRegularKey.ts index deeee77025..a546f41058 100644 --- a/packages/xrpl/src/models/transactions/setRegularKey.ts +++ b/packages/xrpl/src/models/transactions/setRegularKey.ts @@ -1,6 +1,9 @@ -import { ValidationError } from '../../errors' - -import { BaseTransaction, validateBaseTransaction } from './common' +import { + BaseTransaction, + isAccount, + validateBaseTransaction, + validateOptionalField, +} from './common' /** * A SetRegularKey transaction assigns, changes, or removes the regular key @@ -27,7 +30,5 @@ export interface SetRegularKey extends BaseTransaction { export function validateSetRegularKey(tx: Record): void { validateBaseTransaction(tx) - if (tx.RegularKey !== undefined && typeof tx.RegularKey !== 'string') { - throw new ValidationError('SetRegularKey: RegularKey must be a string') - } + validateOptionalField(tx, 'RegularKey', isAccount) } diff --git a/packages/xrpl/src/models/transactions/signerListSet.ts b/packages/xrpl/src/models/transactions/signerListSet.ts index a5ac146924..4831b69399 100644 --- a/packages/xrpl/src/models/transactions/signerListSet.ts +++ b/packages/xrpl/src/models/transactions/signerListSet.ts @@ -4,10 +4,11 @@ import { SignerEntry } from '../common' import { BaseTransaction, isArray, + isHexString, isNumber, isRecord, - isString, validateBaseTransaction, + validateOptionalField, validateRequiredField, } from './common' @@ -36,8 +37,6 @@ export interface SignerListSet extends BaseTransaction { const MAX_SIGNERS = 32 -const HEX_WALLET_LOCATOR_REGEX = /^[0-9A-Fa-f]{64}$/u - /** * Verify the form and type of an SignerListSet at runtime. * @@ -55,6 +54,7 @@ export function validateSignerListSet(tx: Record): void { } validateRequiredField(tx, 'SignerEntries', isArray) + if (tx.SignerEntries.length === 0) { throw new ValidationError( 'SignerListSet: need at least 1 member in SignerEntries', @@ -67,22 +67,16 @@ export function validateSignerListSet(tx: Record): void { ) } - for (const entry of tx.SignerEntries) { + tx.SignerEntries.forEach((entry, index) => { if (!isRecord(entry) || !isRecord(entry.SignerEntry)) { throw new ValidationError( 'SignerListSet: SignerEntries must be an array of SignerEntry objects', ) } const signerEntry = entry.SignerEntry - const { WalletLocator } = signerEntry - if ( - WalletLocator != null && - (!isString(WalletLocator) || - !HEX_WALLET_LOCATOR_REGEX.test(WalletLocator)) - ) { - throw new ValidationError( - `SignerListSet: WalletLocator in SignerEntry must be a 256-bit (32-byte) hexadecimal value`, - ) - } - } + validateOptionalField(signerEntry, 'WalletLocator', isHexString, { + paramName: `SignerEntries[${index}].WalletLocator`, + txType: 'SignerListSet', + }) + }) } diff --git a/packages/xrpl/src/models/transactions/ticketCreate.ts b/packages/xrpl/src/models/transactions/ticketCreate.ts index 3206ffe54e..72d9903d3d 100644 --- a/packages/xrpl/src/models/transactions/ticketCreate.ts +++ b/packages/xrpl/src/models/transactions/ticketCreate.ts @@ -1,6 +1,9 @@ -import { ValidationError } from '../../errors' - -import { BaseTransaction, validateBaseTransaction } from './common' +import { + BaseTransaction, + isNumberWithBounds, + validateBaseTransaction, + validateRequiredField, +} from './common' /** * A TicketCreate transaction sets aside one or more sequence numbers as @@ -28,23 +31,6 @@ const MAX_TICKETS = 250 */ export function validateTicketCreate(tx: Record): void { validateBaseTransaction(tx) - const { TicketCount } = tx - - if (TicketCount === undefined) { - throw new ValidationError('TicketCreate: missing field TicketCount') - } - - if (typeof TicketCount !== 'number') { - throw new ValidationError('TicketCreate: TicketCount must be a number') - } - if ( - !Number.isInteger(TicketCount) || - TicketCount < 1 || - TicketCount > MAX_TICKETS - ) { - throw new ValidationError( - 'TicketCreate: TicketCount must be an integer from 1 to 250', - ) - } + validateRequiredField(tx, 'TicketCount', isNumberWithBounds(1, MAX_TICKETS)) } diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index 97f710a2ea..97257ed2b4 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -23,9 +23,9 @@ import { isIssuedCurrencyAmount, validateBaseTransaction, } from './common' -import { CredentialAccept, validateCredentialAccept } from './CredentialAccept' -import { CredentialCreate, validateCredentialCreate } from './CredentialCreate' -import { CredentialDelete, validateCredentialDelete } from './CredentialDelete' +import { CredentialAccept, validateCredentialAccept } from './credentialAccept' +import { CredentialCreate, validateCredentialCreate } from './credentialCreate' +import { CredentialDelete, validateCredentialDelete } from './credentialDelete' import { DelegateSet, validateDelegateSet } from './delegateSet' import { DepositPreauth, validateDepositPreauth } from './depositPreauth' import { DIDDelete, validateDIDDelete } from './DIDDelete' diff --git a/packages/xrpl/src/models/transactions/trustSet.ts b/packages/xrpl/src/models/transactions/trustSet.ts index 1a9a965c8f..d73806f540 100644 --- a/packages/xrpl/src/models/transactions/trustSet.ts +++ b/packages/xrpl/src/models/transactions/trustSet.ts @@ -1,11 +1,13 @@ -import { ValidationError } from '../../errors' import { IssuedCurrencyAmount } from '../common' import { BaseTransaction, + isNumber, GlobalFlagsInterface, - isAmount, validateBaseTransaction, + validateOptionalField, + validateRequiredField, + isIssuedCurrencyAmount, } from './common' /** @@ -136,21 +138,9 @@ export interface TrustSet extends BaseTransaction { */ export function validateTrustSet(tx: Record): void { validateBaseTransaction(tx) - const { LimitAmount, QualityIn, QualityOut } = tx - if (LimitAmount === undefined) { - throw new ValidationError('TrustSet: missing field LimitAmount') - } + validateRequiredField(tx, 'LimitAmount', isIssuedCurrencyAmount) - if (!isAmount(LimitAmount)) { - throw new ValidationError('TrustSet: invalid LimitAmount') - } - - if (QualityIn !== undefined && typeof QualityIn !== 'number') { - throw new ValidationError('TrustSet: QualityIn must be a number') - } - - if (QualityOut !== undefined && typeof QualityOut !== 'number') { - throw new ValidationError('TrustSet: QualityOut must be a number') - } + validateOptionalField(tx, 'QualityIn', isNumber) + validateOptionalField(tx, 'QualityOut', isNumber) } diff --git a/packages/xrpl/src/models/transactions/vaultClawback.ts b/packages/xrpl/src/models/transactions/vaultClawback.ts index 44e2991afe..babf703c36 100644 --- a/packages/xrpl/src/models/transactions/vaultClawback.ts +++ b/packages/xrpl/src/models/transactions/vaultClawback.ts @@ -4,7 +4,7 @@ import { BaseTransaction, validateBaseTransaction, validateRequiredField, - isString, + isHexString, Account, isAccount, validateOptionalField, @@ -49,7 +49,7 @@ export interface VaultClawback extends BaseTransaction { export function validateVaultClawback(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'VaultID', isString) + validateRequiredField(tx, 'VaultID', isHexString) validateRequiredField(tx, 'Holder', isAccount) validateOptionalField(tx, 'Amount', isClawbackAmount) } diff --git a/packages/xrpl/src/models/transactions/vaultCreate.ts b/packages/xrpl/src/models/transactions/vaultCreate.ts index da3f44c441..2533e958e9 100644 --- a/packages/xrpl/src/models/transactions/vaultCreate.ts +++ b/packages/xrpl/src/models/transactions/vaultCreate.ts @@ -15,10 +15,10 @@ import { isNumber, isCurrency, validateRequiredField, - isString, VAULT_DATA_MAX_BYTE_LENGTH, XRPLNumber, isXRPLNumber, + isHexString, } from './common' const MAX_SCALE = 18 @@ -113,18 +113,15 @@ export function validateVaultCreate(tx: Record): void { validateBaseTransaction(tx) validateRequiredField(tx, 'Asset', isCurrency) - validateOptionalField(tx, 'Data', isString) + validateOptionalField(tx, 'Data', isHexString) validateOptionalField(tx, 'AssetsMaximum', isXRPLNumber) - validateOptionalField(tx, 'MPTokenMetadata', isString) + validateOptionalField(tx, 'MPTokenMetadata', isHexString) validateOptionalField(tx, 'WithdrawalPolicy', isNumber) - validateOptionalField(tx, 'DomainID', isString) + validateOptionalField(tx, 'DomainID', isHexString) validateOptionalField(tx, 'Scale', isNumber) if (tx.Data !== undefined) { const dataHex = tx.Data - if (!isHex(dataHex)) { - throw new ValidationError('VaultCreate: Data must be a valid hex string') - } const dataByteLength = dataHex.length / 2 if (dataByteLength > VAULT_DATA_MAX_BYTE_LENGTH) { throw new ValidationError( diff --git a/packages/xrpl/src/models/transactions/vaultDelete.ts b/packages/xrpl/src/models/transactions/vaultDelete.ts index 78aa9ed474..303853c866 100644 --- a/packages/xrpl/src/models/transactions/vaultDelete.ts +++ b/packages/xrpl/src/models/transactions/vaultDelete.ts @@ -2,7 +2,7 @@ import { BaseTransaction, validateBaseTransaction, validateRequiredField, - isString, + isHexString, } from './common' /** @@ -28,5 +28,5 @@ export interface VaultDelete extends BaseTransaction { export function validateVaultDelete(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'VaultID', isString) + validateRequiredField(tx, 'VaultID', isHexString) } diff --git a/packages/xrpl/src/models/transactions/vaultDeposit.ts b/packages/xrpl/src/models/transactions/vaultDeposit.ts index ce3d3f45c7..16eb2d4d54 100644 --- a/packages/xrpl/src/models/transactions/vaultDeposit.ts +++ b/packages/xrpl/src/models/transactions/vaultDeposit.ts @@ -4,7 +4,7 @@ import { BaseTransaction, validateBaseTransaction, validateRequiredField, - isString, + isHexString, isAmount, } from './common' @@ -37,6 +37,6 @@ export interface VaultDeposit extends BaseTransaction { export function validateVaultDeposit(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'VaultID', isString) + validateRequiredField(tx, 'VaultID', isHexString) validateRequiredField(tx, 'Amount', isAmount) } diff --git a/packages/xrpl/src/models/transactions/vaultSet.ts b/packages/xrpl/src/models/transactions/vaultSet.ts index 9bd2ca971f..a47b502439 100644 --- a/packages/xrpl/src/models/transactions/vaultSet.ts +++ b/packages/xrpl/src/models/transactions/vaultSet.ts @@ -1,15 +1,14 @@ import { ValidationError } from '../../errors' -import { isHex } from '../utils' import { BaseTransaction, validateBaseTransaction, validateOptionalField, validateRequiredField, - isString, VAULT_DATA_MAX_BYTE_LENGTH, XRPLNumber, isXRPLNumber, + isHexString, } from './common' /** @@ -51,16 +50,13 @@ export interface VaultSet extends BaseTransaction { export function validateVaultSet(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'VaultID', isString) - validateOptionalField(tx, 'Data', isString) + validateRequiredField(tx, 'VaultID', isHexString) + validateOptionalField(tx, 'Data', isHexString) validateOptionalField(tx, 'AssetsMaximum', isXRPLNumber) - validateOptionalField(tx, 'DomainID', isString) + validateOptionalField(tx, 'DomainID', isHexString) if (tx.Data !== undefined) { const dataHex = tx.Data - if (!isHex(dataHex)) { - throw new ValidationError('VaultSet: Data must be a valid hex string') - } const dataByteLength = dataHex.length / 2 if (dataByteLength > VAULT_DATA_MAX_BYTE_LENGTH) { throw new ValidationError( diff --git a/packages/xrpl/src/models/transactions/vaultWithdraw.ts b/packages/xrpl/src/models/transactions/vaultWithdraw.ts index ceb5a36e55..3d86efe07a 100644 --- a/packages/xrpl/src/models/transactions/vaultWithdraw.ts +++ b/packages/xrpl/src/models/transactions/vaultWithdraw.ts @@ -4,7 +4,7 @@ import { BaseTransaction, validateBaseTransaction, validateRequiredField, - isString, + isHexString, isAmount, Account, validateOptionalField, @@ -51,7 +51,7 @@ export interface VaultWithdraw extends BaseTransaction { export function validateVaultWithdraw(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'VaultID', isString) + validateRequiredField(tx, 'VaultID', isHexString) validateRequiredField(tx, 'Amount', isAmount) validateOptionalField(tx, 'Destination', isAccount) validateOptionalField(tx, 'DestinationTag', isNumber) diff --git a/packages/xrpl/src/models/utils/index.ts b/packages/xrpl/src/models/utils/index.ts index de3320a4b4..09bea4ec86 100644 --- a/packages/xrpl/src/models/utils/index.ts +++ b/packages/xrpl/src/models/utils/index.ts @@ -1,6 +1,7 @@ import type { Transaction } from '../transactions' -const HEX_REGEX = /^[0-9A-Fa-f]+$/u +const HEX_REGEX = /^[0-9A-Fa-f]*$/u + export const INTEGER_SANITY_CHECK = /^[0-9]+$/u /** @@ -20,13 +21,13 @@ export function onlyHasFields( /** * Perform bitwise AND (&) to check if a flag is enabled within Flags (as a number). * - * @param Flags - A number that represents flags enabled. - * @param checkFlag - A specific flag to check if it's enabled within Flags. - * @returns True if checkFlag is enabled within Flags. + * @param flags - A number that represents flags enabled. + * @param checkFlag - A specific flag to check if it's enabled within flags. + * @returns True if checkFlag is enabled within flags. */ -export function isFlagEnabled(Flags: number, checkFlag: number): boolean { +export function isFlagEnabled(flags: number, checkFlag: number): boolean { // eslint-disable-next-line no-bitwise -- flags need bitwise - return (BigInt(checkFlag) & BigInt(Flags)) === BigInt(checkFlag) + return (BigInt(checkFlag) & BigInt(flags)) === BigInt(checkFlag) } /** diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index bb7809ac98..469615c9dc 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -126,8 +126,8 @@ interface ClassicAccountAndTag { */ export function setValidAddresses(tx: Transaction): void { validateAccountAddress(tx, 'Account', 'SourceTag') - // eslint-disable-next-line @typescript-eslint/dot-notation -- Destination can exist on Transaction - if (tx['Destination'] != null) { + + if ('Destination' in tx) { validateAccountAddress(tx, 'Destination', 'DestinationTag') } @@ -153,15 +153,21 @@ function validateAccountAddress( accountField: string, tagField: string, ): void { + if (!(accountField in tx)) { + throw new ValidationError(`Missing field: ${accountField}`) + } + const val: unknown = tx[accountField] + + if (typeof val !== 'string') { + throw new ValidationError(`${accountField} must be a string`) + } // if X-address is given, convert it to classic address - const { classicAccount, tag } = getClassicAccountAndTag( - tx[accountField] as string, - ) + const { classicAccount, tag } = getClassicAccountAndTag(val) // eslint-disable-next-line no-param-reassign -- param reassign is safe tx[accountField] = classicAccount if (tag != null && tag !== false) { - if (tx[tagField] && tx[tagField] !== tag) { + if (tagField in tx && tx[tagField] !== tag) { throw new ValidationError( `The ${tagField}, if present, must match the tag of the ${accountField} X-address`, ) diff --git a/packages/xrpl/test/integration/transactions/credentialDelete.test.ts b/packages/xrpl/test/integration/transactions/credentialDelete.test.ts index 246397c66f..1e58b731d7 100644 --- a/packages/xrpl/test/integration/transactions/credentialDelete.test.ts +++ b/packages/xrpl/test/integration/transactions/credentialDelete.test.ts @@ -6,7 +6,7 @@ import { CredentialAccept, CredentialCreate, } from '../../../src' -import { CredentialDelete } from '../../../src/models/transactions/CredentialDelete' +import { CredentialDelete } from '../../../src/models/transactions/credentialDelete' import serverUrl from '../serverUrl' import { setupClient, diff --git a/packages/xrpl/test/integration/transactions/permissionedDEX.test.ts b/packages/xrpl/test/integration/transactions/permissionedDEX.test.ts index 7c90b405ac..69d93cc462 100644 --- a/packages/xrpl/test/integration/transactions/permissionedDEX.test.ts +++ b/packages/xrpl/test/integration/transactions/permissionedDEX.test.ts @@ -20,8 +20,8 @@ import { SubscribeBook, SubscribeRequest, } from '../../../src/models/methods/subscribe' -import { CredentialAccept } from '../../../src/models/transactions/CredentialAccept' -import { CredentialCreate } from '../../../src/models/transactions/CredentialCreate' +import { CredentialAccept } from '../../../src/models/transactions/credentialAccept' +import { CredentialCreate } from '../../../src/models/transactions/credentialCreate' import { OfferCreate, OfferCreateFlags, diff --git a/packages/xrpl/test/models/AMMBid.test.ts b/packages/xrpl/test/models/AMMBid.test.ts index 9cb95cfea1..4d224c1dac 100644 --- a/packages/xrpl/test/models/AMMBid.test.ts +++ b/packages/xrpl/test/models/AMMBid.test.ts @@ -72,7 +72,8 @@ describe('AMMBid', function () { it(`throws w/ Asset must be a Currency`, function () { bid.Asset = 1234 - const errorMessage = 'AMMBid: Asset must be a Currency' + const errorMessage = + 'AMMBid: invalid field Asset, expected a valid Currency' assertInvalid(bid, errorMessage) }) @@ -84,19 +85,20 @@ describe('AMMBid', function () { it(`throws w/ Asset2 must be a Currency`, function () { bid.Asset2 = 1234 - const errorMessage = 'AMMBid: Asset2 must be a Currency' + const errorMessage = + 'AMMBid: invalid field Asset2, expected a valid Currency' assertInvalid(bid, errorMessage) }) it(`throws w/ BidMin must be an Amount`, function () { bid.BidMin = 5 - const errorMessage = 'AMMBid: BidMin must be an Amount' + const errorMessage = 'AMMBid: invalid field BidMin, expected a valid Amount' assertInvalid(bid, errorMessage) }) it(`throws w/ BidMax must be an Amount`, function () { bid.BidMax = 10 - const errorMessage = 'AMMBid: BidMax must be an Amount' + const errorMessage = 'AMMBid: invalid field BidMax, expected a valid Amount' assertInvalid(bid, errorMessage) }) @@ -121,7 +123,8 @@ describe('AMMBid', function () { bid.AuthAccounts[0] = { AuthAccount: null, } - const errorMessage = 'AMMBid: invalid AuthAccounts' + const errorMessage = + 'AMMBid: invalid field AuthAccounts[0].AuthAccount, expected a valid Record' assertInvalid(bid, errorMessage) }) @@ -129,7 +132,8 @@ describe('AMMBid', function () { bid.AuthAccounts[0] = { AuthAccount: undefined, } - const errorMessage = 'AMMBid: invalid AuthAccounts' + const errorMessage = + 'AMMBid: invalid field AuthAccounts[0].AuthAccount, expected a valid Record' assertInvalid(bid, errorMessage) }) @@ -137,7 +141,8 @@ describe('AMMBid', function () { bid.AuthAccounts[0] = { AuthAccount: 1234, } - const errorMessage = 'AMMBid: invalid AuthAccounts' + const errorMessage = + 'AMMBid: invalid field AuthAccounts[0].AuthAccount, expected a valid Record' assertInvalid(bid, errorMessage) }) @@ -147,7 +152,8 @@ describe('AMMBid', function () { Account: 1234, }, } - const errorMessage = 'AMMBid: invalid AuthAccounts' + const errorMessage = + 'AMMBid: invalid field AuthAccounts[0].AuthAccount, expected a valid account address' assertInvalid(bid, errorMessage) }) diff --git a/packages/xrpl/test/models/AMMClawback.test.ts b/packages/xrpl/test/models/AMMClawback.test.ts index 065839ee8f..fd69d7caee 100644 --- a/packages/xrpl/test/models/AMMClawback.test.ts +++ b/packages/xrpl/test/models/AMMClawback.test.ts @@ -59,7 +59,8 @@ describe('AMMClawback', function () { it(`throws w/ invalid field Holder`, function () { ammClawback.Holder = 1234 - const errorMessage = 'AMMClawback: invalid field Holder' + const errorMessage = + 'AMMClawback: invalid field Holder, expected a valid account address' assertInvalid(ammClawback, errorMessage) }) @@ -77,7 +78,8 @@ describe('AMMClawback', function () { it(`throws w/ invalid field Asset`, function () { ammClawback.Asset = '1000' - const errorMessage = 'AMMClawback: invalid field Asset' + const errorMessage = + 'AMMClawback: invalid field Asset, expected a valid Issued Currency' assertInvalid(ammClawback, errorMessage) }) @@ -95,13 +97,15 @@ describe('AMMClawback', function () { it(`throws w/ invalid field Asset2`, function () { ammClawback.Asset2 = '1000' - const errorMessage = 'AMMClawback: invalid field Asset2' + const errorMessage = + 'AMMClawback: invalid field Asset2, expected a valid Currency' assertInvalid(ammClawback, errorMessage) }) it(`throws w/ invalid field Amount`, function () { ammClawback.Amount = 1000 - const errorMessage = 'AMMClawback: invalid field Amount' + const errorMessage = + 'AMMClawback: invalid field Amount, expected a valid IOU Amount' assertInvalid(ammClawback, errorMessage) }) diff --git a/packages/xrpl/test/models/AMMCreate.test.ts b/packages/xrpl/test/models/AMMCreate.test.ts index d785bf001d..b8e0ca6ecb 100644 --- a/packages/xrpl/test/models/AMMCreate.test.ts +++ b/packages/xrpl/test/models/AMMCreate.test.ts @@ -40,7 +40,8 @@ describe('AMMCreate', function () { it(`throws w/ Amount must be an Amount`, function () { ammCreate.Amount = 1000 - const errorMessage = 'AMMCreate: Amount must be an Amount' + const errorMessage = + 'AMMCreate: invalid field Amount, expected a valid Amount' assertInvalid(ammCreate, errorMessage) }) @@ -52,7 +53,8 @@ describe('AMMCreate', function () { it(`throws w/ Amount2 must be an Amount`, function () { ammCreate.Amount2 = 1000 - const errorMessage = 'AMMCreate: Amount2 must be an Amount' + const errorMessage = + 'AMMCreate: invalid field Amount2, expected a valid Amount' assertInvalid(ammCreate, errorMessage) }) @@ -63,20 +65,23 @@ describe('AMMCreate', function () { }) it(`throws w/ TradingFee must be a number`, function () { - ammCreate.TradingFee = '12' - const errorMessage = 'AMMCreate: TradingFee must be a number' + ammCreate.TradingFee = 'abcd' + const errorMessage = + 'AMMCreate: invalid field TradingFee, expected a valid number' assertInvalid(ammCreate, errorMessage) }) it(`throws when TradingFee is greater than 1000`, function () { ammCreate.TradingFee = 1001 - const errorMessage = 'AMMCreate: TradingFee must be between 0 and 1000' + const errorMessage = + 'AMMCreate: invalid field TradingFee, expected a valid number' assertInvalid(ammCreate, errorMessage) }) it(`throws when TradingFee is a negative number`, function () { ammCreate.TradingFee = -1 - const errorMessage = 'AMMCreate: TradingFee must be between 0 and 1000' + const errorMessage = + 'AMMCreate: invalid field TradingFee, expected a valid number' assertInvalid(ammCreate, errorMessage) }) }) diff --git a/packages/xrpl/test/models/AMMDelete.test.ts b/packages/xrpl/test/models/AMMDelete.test.ts index 4d81bfaa39..0f4761eb7b 100644 --- a/packages/xrpl/test/models/AMMDelete.test.ts +++ b/packages/xrpl/test/models/AMMDelete.test.ts @@ -41,7 +41,8 @@ describe('AMMDelete', function () { it(`throws w/ Asset must be a Currency`, function () { ammDelete.Asset = 1234 - const errorMessage = 'AMMDelete: Asset must be a Currency' + const errorMessage = + 'AMMDelete: invalid field Asset, expected a valid Currency' assertInvalid(ammDelete, errorMessage) }) @@ -53,7 +54,8 @@ describe('AMMDelete', function () { it(`throws w/ Asset2 must be a Currency`, function () { ammDelete.Asset2 = 1234 - const errorMessage = 'AMMDelete: Asset2 must be a Currency' + const errorMessage = + 'AMMDelete: invalid field Asset2, expected a valid Currency' assertInvalid(ammDelete, errorMessage) }) }) diff --git a/packages/xrpl/test/models/AMMDeposit.test.ts b/packages/xrpl/test/models/AMMDeposit.test.ts index d80a49b0d3..24fb20b273 100644 --- a/packages/xrpl/test/models/AMMDeposit.test.ts +++ b/packages/xrpl/test/models/AMMDeposit.test.ts @@ -82,7 +82,8 @@ describe('AMMDeposit', function () { it(`throws w/ Asset must be a Currency`, function () { deposit.Asset = 1234 - const errorMessage = 'AMMDeposit: Asset must be a Currency' + const errorMessage = + 'AMMDeposit: invalid field Asset, expected a valid Currency' assertInvalid(deposit, errorMessage) }) @@ -94,7 +95,8 @@ describe('AMMDeposit', function () { it(`throws w/ Asset2 must be a Currency`, function () { deposit.Asset2 = 1234 - const errorMessage = 'AMMDeposit: Asset2 must be a Currency' + const errorMessage = + 'AMMDeposit: invalid field Asset2, expected a valid Currency' assertInvalid(deposit, errorMessage) }) @@ -122,27 +124,30 @@ describe('AMMDeposit', function () { it(`throws w/ LPTokenOut must be an IssuedCurrencyAmount`, function () { deposit.LPTokenOut = 1234 const errorMessage = - 'AMMDeposit: LPTokenOut must be an IssuedCurrencyAmount' + 'AMMDeposit: invalid field LPTokenOut, expected a valid IOU Amount' assertInvalid(deposit, errorMessage) }) it(`throws w/ Amount must be an Amount`, function () { deposit.Amount = 1234 - const errorMessage = 'AMMDeposit: Amount must be an Amount' + const errorMessage = + 'AMMDeposit: invalid field Amount, expected a valid Amount' assertInvalid(deposit, errorMessage) }) it(`throws w/ Amount2 must be an Amount`, function () { deposit.Amount = '1000' deposit.Amount2 = 1234 - const errorMessage = 'AMMDeposit: Amount2 must be an Amount' + const errorMessage = + 'AMMDeposit: invalid field Amount2, expected a valid Amount' assertInvalid(deposit, errorMessage) }) it(`throws w/ EPrice must be an Amount`, function () { deposit.Amount = '1000' deposit.EPrice = 1234 - const errorMessage = 'AMMDeposit: EPrice must be an Amount' + const errorMessage = + 'AMMDeposit: invalid field EPrice, expected a valid Amount' assertInvalid(deposit, errorMessage) }) }) diff --git a/packages/xrpl/test/models/AMMVote.test.ts b/packages/xrpl/test/models/AMMVote.test.ts index 71a4e78f27..1dc8b80fb1 100644 --- a/packages/xrpl/test/models/AMMVote.test.ts +++ b/packages/xrpl/test/models/AMMVote.test.ts @@ -41,7 +41,8 @@ describe('AMMVote', function () { it(`throws w/ Asset must be a Currency`, function () { vote.Asset = 1234 - const errorMessage = 'AMMVote: Asset must be a Currency' + const errorMessage = + 'AMMVote: invalid field Asset, expected a valid Currency' assertInvalid(vote, errorMessage) }) @@ -53,7 +54,8 @@ describe('AMMVote', function () { it(`throws w/ Asset2 must be a Currency`, function () { vote.Asset2 = 1234 - const errorMessage = 'AMMVote: Asset2 must be a Currency' + const errorMessage = + 'AMMVote: invalid field Asset2, expected a valid Currency' assertInvalid(vote, errorMessage) }) @@ -64,20 +66,23 @@ describe('AMMVote', function () { }) it(`throws w/ TradingFee must be a number`, function () { - vote.TradingFee = '25' - const errorMessage = 'AMMVote: TradingFee must be a number' + vote.TradingFee = 'abcd' + const errorMessage = + 'AMMVote: invalid field TradingFee, expected a valid number' assertInvalid(vote, errorMessage) }) it(`throws when TradingFee is greater than AMM_MAX_TRADING_FEE`, function () { vote.TradingFee = 1001 - const errorMessage = 'AMMVote: TradingFee must be between 0 and 1000' + const errorMessage = + 'AMMVote: invalid field TradingFee, expected a valid number' assertInvalid(vote, errorMessage) }) it(`throws when TradingFee is a negative number`, function () { vote.TradingFee = -1 - const errorMessage = 'AMMVote: TradingFee must be between 0 and 1000' + const errorMessage = + 'AMMVote: invalid field TradingFee, expected a valid number' assertInvalid(vote, errorMessage) }) }) diff --git a/packages/xrpl/test/models/AMMWithdraw.test.ts b/packages/xrpl/test/models/AMMWithdraw.test.ts index bf126b1085..ab4bf28650 100644 --- a/packages/xrpl/test/models/AMMWithdraw.test.ts +++ b/packages/xrpl/test/models/AMMWithdraw.test.ts @@ -93,7 +93,8 @@ describe('AMMWithdraw', function () { it(`throws w/ Asset must be a Currency`, function () { withdraw.Asset = 1234 - const errorMessage = 'AMMWithdraw: Asset must be a Currency' + const errorMessage = + 'AMMWithdraw: invalid field Asset, expected a valid Currency' assertInvalid(withdraw, errorMessage) }) @@ -103,9 +104,10 @@ describe('AMMWithdraw', function () { assertInvalid(withdraw, errorMessage) }) - it(`throws w/ Asset2 must be a Currency`, function () { + it(`throws when Asset2 is not a Currency`, function () { withdraw.Asset2 = 1234 - const errorMessage = 'AMMWithdraw: Asset2 must be a Currency' + const errorMessage = + 'AMMWithdraw: invalid field Asset2, expected a valid Currency' assertInvalid(withdraw, errorMessage) }) @@ -125,30 +127,33 @@ describe('AMMWithdraw', function () { assertInvalid(withdraw, errorMessage) }) - it(`throws w/ LPTokenIn must be an IssuedCurrencyAmount`, function () { + it(`throws when LPTokenIn is not an IssuedCurrencyAmount`, function () { withdraw.LPTokenIn = 1234 const errorMessage = - 'AMMWithdraw: LPTokenIn must be an IssuedCurrencyAmount' + 'AMMWithdraw: invalid field LPTokenIn, expected a valid IOU Amount' assertInvalid(withdraw, errorMessage) }) - it(`throws w/ Amount must be an Amount`, function () { + it(`throws when Amount is not an Amount`, function () { withdraw.Amount = 1234 - const errorMessage = 'AMMWithdraw: Amount must be an Amount' + const errorMessage = + 'AMMWithdraw: invalid field Amount, expected a valid Amount' assertInvalid(withdraw, errorMessage) }) - it(`throws w/ Amount2 must be an Amount`, function () { + it(`throws when Amount2 is not an Amount`, function () { withdraw.Amount = '1000' withdraw.Amount2 = 1234 - const errorMessage = 'AMMWithdraw: Amount2 must be an Amount' + const errorMessage = + 'AMMWithdraw: invalid field Amount2, expected a valid Amount' assertInvalid(withdraw, errorMessage) }) - it(`throws w/ EPrice must be an Amount`, function () { + it(`throws when EPrice is not an Amount`, function () { withdraw.Amount = '1000' withdraw.EPrice = 1234 - const errorMessage = 'AMMWithdraw: EPrice must be an Amount' + const errorMessage = + 'AMMWithdraw: invalid field EPrice, expected a valid Amount' assertInvalid(withdraw, errorMessage) }) }) diff --git a/packages/xrpl/test/models/CredentialAccept.test.ts b/packages/xrpl/test/models/CredentialAccept.test.ts index fbf4f80668..0617703348 100644 --- a/packages/xrpl/test/models/CredentialAccept.test.ts +++ b/packages/xrpl/test/models/CredentialAccept.test.ts @@ -1,6 +1,6 @@ import { stringToHex } from '@xrplf/isomorphic/utils' -import { validateCredentialAccept } from '../../src/models/transactions/CredentialAccept' +import { validateCredentialAccept } from '../../src/models/transactions/credentialAccept' import { assertTxIsValid, assertTxValidationError } from '../testUtils' const assertValid = (tx: any): void => @@ -39,7 +39,8 @@ describe('CredentialAccept', function () { it(`throws w/ Account not a string`, function () { credentialAccept.Account = 123 - const errorMessage = 'CredentialAccept: invalid field Account' + const errorMessage = + 'CredentialAccept: invalid field Account, expected a valid account address' assertInvalid(credentialAccept, errorMessage) }) @@ -51,7 +52,8 @@ describe('CredentialAccept', function () { it(`throws w/ Issuer not a string`, function () { credentialAccept.Issuer = 123 - const errorMessage = 'CredentialAccept: invalid field Issuer' + const errorMessage = + 'CredentialAccept: invalid field Issuer, expected a valid account address' assertInvalid(credentialAccept, errorMessage) }) @@ -78,7 +80,7 @@ describe('CredentialAccept', function () { it(`throws w/ credentialType field not hex`, function () { credentialAccept.CredentialType = 'this is not hex' const errorMessage = - 'CredentialAccept: CredentialType must be encoded in hex' + 'CredentialAccept: invalid field CredentialType, expected a valid hex string' assertInvalid(credentialAccept, errorMessage) }) }) diff --git a/packages/xrpl/test/models/CredentialCreate.test.ts b/packages/xrpl/test/models/CredentialCreate.test.ts index 4debc22a86..d294f5f788 100644 --- a/packages/xrpl/test/models/CredentialCreate.test.ts +++ b/packages/xrpl/test/models/CredentialCreate.test.ts @@ -1,6 +1,6 @@ import { stringToHex } from '@xrplf/isomorphic/utils' -import { validateCredentialCreate } from '../../src/models/transactions/CredentialCreate' +import { validateCredentialCreate } from '../../src/models/transactions/credentialCreate' import { assertTxIsValid, assertTxValidationError } from '../testUtils' const assertValid = (tx: any): void => @@ -41,7 +41,8 @@ describe('credentialCreate', function () { it(`throws w/ Account not string`, function () { credentialCreate.Account = 123 - const errorMessage = 'CredentialCreate: invalid field Account' + const errorMessage = + 'CredentialCreate: invalid field Account, expected a valid account address' assertInvalid(credentialCreate, errorMessage) }) @@ -53,7 +54,8 @@ describe('credentialCreate', function () { it(`throws w/ Subject not string`, function () { credentialCreate.Subject = 123 - const errorMessage = 'CredentialCreate: invalid field Subject' + const errorMessage = + 'CredentialCreate: invalid field Subject, expected a valid account address' assertInvalid(credentialCreate, errorMessage) }) @@ -80,19 +82,21 @@ describe('credentialCreate', function () { it(`throws w/ credentialType field not hex`, function () { credentialCreate.CredentialType = 'this is not hex' const errorMessage = - 'CredentialCreate: CredentialType must be encoded in hex' + 'CredentialCreate: invalid field CredentialType, expected a valid hex string' assertInvalid(credentialCreate, errorMessage) }) it(`throws w/ Expiration field not number`, function () { credentialCreate.Expiration = 'this is not a number' - const errorMessage = 'CredentialCreate: invalid field Expiration' + const errorMessage = + 'CredentialCreate: invalid field Expiration, expected a valid number' assertInvalid(credentialCreate, errorMessage) }) it(`throws w/ URI field not a string`, function () { credentialCreate.URI = 123 - const errorMessage = 'CredentialCreate: invalid field URI' + const errorMessage = + 'CredentialCreate: invalid field URI, expected a valid hex string' assertInvalid(credentialCreate, errorMessage) }) @@ -110,7 +114,8 @@ describe('credentialCreate', function () { it(`throws w/ URI field not hex`, function () { credentialCreate.URI = 'this is not hex' - const errorMessage = 'CredentialCreate: URI must be encoded in hex' + const errorMessage = + 'CredentialCreate: invalid field URI, expected a valid hex string' assertInvalid(credentialCreate, errorMessage) }) }) diff --git a/packages/xrpl/test/models/CredentialDelete.test.ts b/packages/xrpl/test/models/CredentialDelete.test.ts index 4b08bd1949..3966a0c8c6 100644 --- a/packages/xrpl/test/models/CredentialDelete.test.ts +++ b/packages/xrpl/test/models/CredentialDelete.test.ts @@ -1,6 +1,6 @@ import { stringToHex } from '@xrplf/isomorphic/utils' -import { validateCredentialDelete } from '../../src/models/transactions/CredentialDelete' +import { validateCredentialDelete } from '../../src/models/transactions/credentialDelete' import { assertTxIsValid, assertTxValidationError } from '../testUtils' const assertValid = (tx: any): void => @@ -40,19 +40,22 @@ describe('CredentialDelete', function () { it(`throws w/ Account not string`, function () { credentialDelete.Account = 123 - const errorMessage = 'CredentialDelete: invalid field Account' + const errorMessage = + 'CredentialDelete: invalid field Account, expected a valid account address' assertInvalid(credentialDelete, errorMessage) }) it(`throws w/ Subject not string`, function () { credentialDelete.Subject = 123 - const errorMessage = 'CredentialDelete: invalid field Subject' + const errorMessage = + 'CredentialDelete: invalid field Subject, expected a valid account address' assertInvalid(credentialDelete, errorMessage) }) it(`throws w/ Issuer not string`, function () { credentialDelete.Issuer = 123 - const errorMessage = 'CredentialDelete: invalid field Issuer' + const errorMessage = + 'CredentialDelete: invalid field Issuer, expected a valid account address' assertInvalid(credentialDelete, errorMessage) }) @@ -87,7 +90,7 @@ describe('CredentialDelete', function () { it(`throws w/ credentialType field not hex`, function () { credentialDelete.CredentialType = 'this is not hex' const errorMessage = - 'CredentialDelete: CredentialType must be encoded in hex' + 'CredentialDelete: invalid field CredentialType, expected a valid hex string' assertInvalid(credentialDelete, errorMessage) }) }) diff --git a/packages/xrpl/test/models/DIDSet.test.ts b/packages/xrpl/test/models/DIDSet.test.ts index 0aae8287b2..8e9dba5bac 100644 --- a/packages/xrpl/test/models/DIDSet.test.ts +++ b/packages/xrpl/test/models/DIDSet.test.ts @@ -33,19 +33,22 @@ describe('DIDSet', function () { it('throws w/ invalid Data', function () { tx.Data = 123 - assertInvalid(tx, 'DIDSet: invalid field Data') + assertInvalid(tx, 'DIDSet: invalid field Data, expected a valid hex string') }) it('throws w/ invalid DIDDocument', function () { tx.DIDDocument = 123 - assertInvalid(tx, 'DIDSet: invalid field DIDDocument') + assertInvalid( + tx, + 'DIDSet: invalid field DIDDocument, expected a valid hex string', + ) }) it('throws w/ invalid URI', function () { tx.URI = 123 - assertInvalid(tx, 'DIDSet: invalid field URI') + assertInvalid(tx, 'DIDSet: invalid field URI, expected a valid hex string') }) it('throws w/ empty DID', function () { diff --git a/packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts b/packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts index 3e3c241e6d..8d657a5765 100644 --- a/packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts +++ b/packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts @@ -1,11 +1,8 @@ -import { stringToHex } from '@xrplf/isomorphic/src/utils' +import { stringToHex } from '@xrplf/isomorphic/utils' import { MPTokenIssuanceCreateFlags, MPTokenMetadata } from '../../src' import { validateMPTokenIssuanceCreate } from '../../src/models/transactions/MPTokenIssuanceCreate' -import { - MAX_MPT_META_BYTE_LENGTH, - MPT_META_WARNING_HEADER, -} from '../../src/models/utils/mptokenMetadata' +import { MPT_META_WARNING_HEADER } from '../../src/models/utils/mptokenMetadata' import { assertTxIsValid, assertTxValidationError } from '../testUtils' const assertValid = (tx: any): void => @@ -51,7 +48,7 @@ describe('MPTokenIssuanceCreate', function () { assertInvalid( invalid, - `MPTokenIssuanceCreate: MPTokenMetadata (hex format) must be non-empty and no more than ${MAX_MPT_META_BYTE_LENGTH} bytes.`, + `MPTokenIssuanceCreate: MPTokenMetadata must not be empty string`, ) }) @@ -65,7 +62,7 @@ describe('MPTokenIssuanceCreate', function () { assertInvalid( invalid, - `MPTokenIssuanceCreate: MPTokenMetadata (hex format) must be non-empty and no more than ${MAX_MPT_META_BYTE_LENGTH} bytes.`, + 'MPTokenIssuanceCreate: invalid field MPTokenMetadata, expected a valid hex string', ) }) diff --git a/packages/xrpl/test/models/NFTokenAcceptOffer.test.ts b/packages/xrpl/test/models/NFTokenAcceptOffer.test.ts index 6a91d8ef4f..8e84925880 100644 --- a/packages/xrpl/test/models/NFTokenAcceptOffer.test.ts +++ b/packages/xrpl/test/models/NFTokenAcceptOffer.test.ts @@ -169,6 +169,9 @@ describe('NFTokenAcceptOffer', function () { Flags: 2147483648, } as any - assertInvalid(invalid, 'NFTokenAcceptOffer: invalid NFTokenBrokerFee') + assertInvalid( + invalid, + 'NFTokenAcceptOffer: invalid field NFTokenBrokerFee, expected a valid Amount', + ) }) }) diff --git a/packages/xrpl/test/models/NFTokenCreateOffer.test.ts b/packages/xrpl/test/models/NFTokenCreateOffer.test.ts index b287e70cce..8fe50c9afb 100644 --- a/packages/xrpl/test/models/NFTokenCreateOffer.test.ts +++ b/packages/xrpl/test/models/NFTokenCreateOffer.test.ts @@ -131,7 +131,10 @@ describe('NFTokenCreateOffer', function () { Sequence: 2470665, } as any - assertInvalid(invalid, 'NFTokenCreateOffer: invalid Amount') + assertInvalid( + invalid, + 'NFTokenCreateOffer: invalid field Amount, expected a valid Amount', + ) }) it(`throws w/ missing Amount`, function () { @@ -146,7 +149,7 @@ describe('NFTokenCreateOffer', function () { Sequence: 2470665, } as any - assertInvalid(invalid, 'NFTokenCreateOffer: invalid Amount') + assertInvalid(invalid, 'NFTokenCreateOffer: missing field Amount') }) it(`throws w/ Owner for sell offer`, function () { diff --git a/packages/xrpl/test/models/NFTokenMint.test.ts b/packages/xrpl/test/models/NFTokenMint.test.ts index 74fc586d17..29bc1bd08b 100644 --- a/packages/xrpl/test/models/NFTokenMint.test.ts +++ b/packages/xrpl/test/models/NFTokenMint.test.ts @@ -1,4 +1,4 @@ -import { stringToHex } from '@xrplf/isomorphic/src/utils' +import { stringToHex } from '@xrplf/isomorphic/utils' import { NFTokenMintFlags } from '../../src' import { validateNFTokenMint } from '../../src/models/transactions/NFTokenMint' @@ -108,7 +108,10 @@ describe('NFTokenMint', function () { URI: 'http://xrpl.org', } as any - assertInvalid(invalid, 'NFTokenMint: URI must be in hex format') + assertInvalid( + invalid, + 'NFTokenMint: invalid field URI, expected a valid hex string', + ) }) it(`throws when Amount is null but Expiration is present`, function () { diff --git a/packages/xrpl/test/models/NFTokenModify.test.ts b/packages/xrpl/test/models/NFTokenModify.test.ts index e8168c1bd7..87fb6c0dd1 100644 --- a/packages/xrpl/test/models/NFTokenModify.test.ts +++ b/packages/xrpl/test/models/NFTokenModify.test.ts @@ -1,4 +1,4 @@ -import { stringToHex } from '@xrplf/isomorphic/src/utils' +import { stringToHex } from '@xrplf/isomorphic/utils' import { validateNFTokenModify } from '../../src/models/transactions/NFTokenModify' import { assertTxIsValid, assertTxValidationError } from '../testUtils' @@ -64,6 +64,9 @@ describe('NFTokenModify', function () { URI: '--', } as any - assertInvalid(invalid, 'NFTokenModify: URI must be in hex format') + assertInvalid( + invalid, + 'NFTokenModify: invalid field URI, expected a valid hex string', + ) }) }) diff --git a/packages/xrpl/test/models/XChainAccountCreateCommit.test.ts b/packages/xrpl/test/models/XChainAccountCreateCommit.test.ts index fa75c98e26..a77328420c 100644 --- a/packages/xrpl/test/models/XChainAccountCreateCommit.test.ts +++ b/packages/xrpl/test/models/XChainAccountCreateCommit.test.ts @@ -50,7 +50,10 @@ describe('XChainAccountCreateCommit', function () { it('throws w/ invalid XChainBridge', function () { tx.XChainBridge = { XChainDoor: 'test' } - assertInvalid(tx, 'XChainAccountCreateCommit: invalid field XChainBridge') + assertInvalid( + tx, + 'XChainAccountCreateCommit: invalid field XChainBridge, expected a valid XChainBridge object', + ) }) it('throws w/ missing SignatureReward', function () { @@ -67,7 +70,7 @@ describe('XChainAccountCreateCommit', function () { assertInvalid( tx, - 'XChainAccountCreateCommit: invalid field SignatureReward', + 'XChainAccountCreateCommit: invalid field SignatureReward, expected a valid Amount', ) }) @@ -80,7 +83,10 @@ describe('XChainAccountCreateCommit', function () { it('throws w/ invalid Destination', function () { tx.Destination = 123 - assertInvalid(tx, 'XChainAccountCreateCommit: invalid field Destination') + assertInvalid( + tx, + 'XChainAccountCreateCommit: invalid field Destination, expected a valid account address', + ) }) it('throws w/ missing Amount', function () { @@ -92,6 +98,9 @@ describe('XChainAccountCreateCommit', function () { it('throws w/ invalid Amount', function () { tx.Amount = { currency: 'ETH' } - assertInvalid(tx, 'XChainAccountCreateCommit: invalid field Amount') + assertInvalid( + tx, + 'XChainAccountCreateCommit: invalid field Amount, expected a valid Amount', + ) }) }) diff --git a/packages/xrpl/test/models/XChainAddAccountCreateAttestation.test.ts b/packages/xrpl/test/models/XChainAddAccountCreateAttestation.test.ts index 144a43a584..a84c783e1d 100644 --- a/packages/xrpl/test/models/XChainAddAccountCreateAttestation.test.ts +++ b/packages/xrpl/test/models/XChainAddAccountCreateAttestation.test.ts @@ -64,7 +64,10 @@ describe('XChainAddAccountCreateAttestation', function () { it('throws w/ invalid Amount', function () { tx.Amount = { currency: 'ETH' } - assertInvalid(tx, 'XChainAddAccountCreateAttestation: invalid field Amount') + assertInvalid( + tx, + 'XChainAddAccountCreateAttestation: invalid field Amount, expected a valid Amount', + ) }) it('throws w/ missing AttestationRewardAccount', function () { @@ -81,7 +84,7 @@ describe('XChainAddAccountCreateAttestation', function () { assertInvalid( tx, - 'XChainAddAccountCreateAttestation: invalid field AttestationRewardAccount', + 'XChainAddAccountCreateAttestation: invalid field AttestationRewardAccount, expected a valid account address', ) }) @@ -99,7 +102,7 @@ describe('XChainAddAccountCreateAttestation', function () { assertInvalid( tx, - 'XChainAddAccountCreateAttestation: invalid field AttestationSignerAccount', + 'XChainAddAccountCreateAttestation: invalid field AttestationSignerAccount, expected a valid account address', ) }) @@ -117,7 +120,7 @@ describe('XChainAddAccountCreateAttestation', function () { assertInvalid( tx, - 'XChainAddAccountCreateAttestation: invalid field Destination', + 'XChainAddAccountCreateAttestation: invalid field Destination, expected a valid account address', ) }) @@ -135,7 +138,7 @@ describe('XChainAddAccountCreateAttestation', function () { assertInvalid( tx, - 'XChainAddAccountCreateAttestation: invalid field OtherChainSource', + 'XChainAddAccountCreateAttestation: invalid field OtherChainSource, expected a valid account address', ) }) @@ -153,7 +156,7 @@ describe('XChainAddAccountCreateAttestation', function () { assertInvalid( tx, - 'XChainAddAccountCreateAttestation: invalid field PublicKey', + 'XChainAddAccountCreateAttestation: invalid field PublicKey, expected a valid hex string', ) }) @@ -171,7 +174,7 @@ describe('XChainAddAccountCreateAttestation', function () { assertInvalid( tx, - 'XChainAddAccountCreateAttestation: invalid field Signature', + 'XChainAddAccountCreateAttestation: invalid field Signature, expected a valid hex string', ) }) @@ -189,7 +192,7 @@ describe('XChainAddAccountCreateAttestation', function () { assertInvalid( tx, - 'XChainAddAccountCreateAttestation: invalid field SignatureReward', + 'XChainAddAccountCreateAttestation: invalid field SignatureReward, expected a valid Amount', ) }) @@ -207,7 +210,7 @@ describe('XChainAddAccountCreateAttestation', function () { assertInvalid( tx, - 'XChainAddAccountCreateAttestation: invalid field WasLockingChainSend', + 'XChainAddAccountCreateAttestation: invalid field WasLockingChainSend, expected 0 or 1', ) }) @@ -225,7 +228,7 @@ describe('XChainAddAccountCreateAttestation', function () { assertInvalid( tx, - 'XChainAddAccountCreateAttestation: invalid field XChainAccountCreateCount', + 'XChainAddAccountCreateAttestation: invalid field XChainAccountCreateCount, expected a valid number or hex string', ) }) @@ -243,7 +246,7 @@ describe('XChainAddAccountCreateAttestation', function () { assertInvalid( tx, - 'XChainAddAccountCreateAttestation: invalid field XChainBridge', + 'XChainAddAccountCreateAttestation: invalid field XChainBridge, expected a valid XChainBridge object', ) }) }) diff --git a/packages/xrpl/test/models/XChainAddClaimAttestation.test.ts b/packages/xrpl/test/models/XChainAddClaimAttestation.test.ts index 92783d9219..9cf8f0f144 100644 --- a/packages/xrpl/test/models/XChainAddClaimAttestation.test.ts +++ b/packages/xrpl/test/models/XChainAddClaimAttestation.test.ts @@ -58,7 +58,10 @@ describe('XChainAddClaimAttestation', function () { it('throws w/ invalid Amount', function () { tx.Amount = { currency: 'ETH' } - assertInvalid(tx, 'XChainAddClaimAttestation: invalid field Amount') + assertInvalid( + tx, + 'XChainAddClaimAttestation: invalid field Amount, expected a valid Amount', + ) }) it('throws w/ missing AttestationRewardAccount', function () { @@ -75,7 +78,7 @@ describe('XChainAddClaimAttestation', function () { assertInvalid( tx, - 'XChainAddClaimAttestation: invalid field AttestationRewardAccount', + 'XChainAddClaimAttestation: invalid field AttestationRewardAccount, expected a valid account address', ) }) @@ -93,14 +96,17 @@ describe('XChainAddClaimAttestation', function () { assertInvalid( tx, - 'XChainAddClaimAttestation: invalid field AttestationSignerAccount', + 'XChainAddClaimAttestation: invalid field AttestationSignerAccount, expected a valid account address', ) }) it('throws w/ invalid Destination', function () { tx.Destination = 123 - assertInvalid(tx, 'XChainAddClaimAttestation: invalid field Destination') + assertInvalid( + tx, + 'XChainAddClaimAttestation: invalid field Destination, expected a valid account address', + ) }) it('throws w/ missing OtherChainSource', function () { @@ -117,7 +123,7 @@ describe('XChainAddClaimAttestation', function () { assertInvalid( tx, - 'XChainAddClaimAttestation: invalid field OtherChainSource', + 'XChainAddClaimAttestation: invalid field OtherChainSource, expected a valid account address', ) }) @@ -130,7 +136,10 @@ describe('XChainAddClaimAttestation', function () { it('throws w/ invalid PublicKey', function () { tx.PublicKey = 123 - assertInvalid(tx, 'XChainAddClaimAttestation: invalid field PublicKey') + assertInvalid( + tx, + 'XChainAddClaimAttestation: invalid field PublicKey, expected a valid hex string', + ) }) it('throws w/ missing Signature', function () { @@ -142,7 +151,10 @@ describe('XChainAddClaimAttestation', function () { it('throws w/ invalid Signature', function () { tx.Signature = 123 - assertInvalid(tx, 'XChainAddClaimAttestation: invalid field Signature') + assertInvalid( + tx, + 'XChainAddClaimAttestation: invalid field Signature, expected a valid hex string', + ) }) it('throws w/ missing WasLockingChainSend', function () { @@ -159,7 +171,7 @@ describe('XChainAddClaimAttestation', function () { assertInvalid( tx, - 'XChainAddClaimAttestation: invalid field WasLockingChainSend', + 'XChainAddClaimAttestation: invalid field WasLockingChainSend, expected 0 or 1', ) }) @@ -172,7 +184,10 @@ describe('XChainAddClaimAttestation', function () { it('throws w/ invalid XChainBridge', function () { tx.XChainBridge = { XChainDoor: 'test' } - assertInvalid(tx, 'XChainAddClaimAttestation: invalid field XChainBridge') + assertInvalid( + tx, + 'XChainAddClaimAttestation: invalid field XChainBridge, expected a valid XChainBridge object', + ) }) it('throws w/ missing XChainClaimID', function () { @@ -184,6 +199,9 @@ describe('XChainAddClaimAttestation', function () { it('throws w/ invalid XChainClaimID', function () { tx.XChainClaimID = { currency: 'ETH' } - assertInvalid(tx, 'XChainAddClaimAttestation: invalid field XChainClaimID') + assertInvalid( + tx, + 'XChainAddClaimAttestation: invalid field XChainClaimID, expected a valid number or hex string', + ) }) }) diff --git a/packages/xrpl/test/models/XChainClaim.test.ts b/packages/xrpl/test/models/XChainClaim.test.ts index 8ec461224d..218353992c 100644 --- a/packages/xrpl/test/models/XChainClaim.test.ts +++ b/packages/xrpl/test/models/XChainClaim.test.ts @@ -49,7 +49,10 @@ describe('XChainClaim', function () { it('throws w/ invalid XChainBridge', function () { tx.XChainBridge = { XChainDoor: 'test' } - assertInvalid(tx, 'XChainClaim: invalid field XChainBridge') + assertInvalid( + tx, + 'XChainClaim: invalid field XChainBridge, expected a valid XChainBridge object', + ) }) it('throws w/ missing XChainClaimID', function () { @@ -61,7 +64,10 @@ describe('XChainClaim', function () { it('throws w/ invalid XChainClaimID', function () { tx.XChainClaimID = { currency: 'ETH' } - assertInvalid(tx, 'XChainClaim: invalid field XChainClaimID') + assertInvalid( + tx, + 'XChainClaim: invalid field XChainClaimID, expected a valid number or hex string', + ) }) it('throws w/ missing Destination', function () { @@ -73,13 +79,19 @@ describe('XChainClaim', function () { it('throws w/ invalid Destination', function () { tx.Destination = 123 - assertInvalid(tx, 'XChainClaim: invalid field Destination') + assertInvalid( + tx, + 'XChainClaim: invalid field Destination, expected a valid account address', + ) }) it('throws w/ invalid DestinationTag', function () { tx.DestinationTag = 'number' - assertInvalid(tx, 'XChainClaim: invalid field DestinationTag') + assertInvalid( + tx, + 'XChainClaim: invalid field DestinationTag, expected a valid number', + ) }) it('throws w/ missing Amount', function () { @@ -91,6 +103,9 @@ describe('XChainClaim', function () { it('throws w/ invalid Amount', function () { tx.Amount = { currency: 'ETH' } - assertInvalid(tx, 'XChainClaim: invalid field Amount') + assertInvalid( + tx, + 'XChainClaim: invalid field Amount, expected a valid Amount', + ) }) }) diff --git a/packages/xrpl/test/models/XChainCommit.test.ts b/packages/xrpl/test/models/XChainCommit.test.ts index 2d2952a8eb..7b6e287a86 100644 --- a/packages/xrpl/test/models/XChainCommit.test.ts +++ b/packages/xrpl/test/models/XChainCommit.test.ts @@ -48,7 +48,10 @@ describe('XChainCommit', function () { it('throws w/ invalid XChainBridge', function () { tx.XChainBridge = { XChainDoor: 'test' } - assertInvalid(tx, 'XChainCommit: invalid field XChainBridge') + assertInvalid( + tx, + 'XChainCommit: invalid field XChainBridge, expected a valid XChainBridge object', + ) }) it('throws w/ missing XChainClaimID', function () { @@ -60,13 +63,19 @@ describe('XChainCommit', function () { it('throws w/ invalid XChainClaimID', function () { tx.XChainClaimID = { currency: 'ETH' } - assertInvalid(tx, 'XChainCommit: invalid field XChainClaimID') + assertInvalid( + tx, + 'XChainCommit: invalid field XChainClaimID, expected a valid number or hex string', + ) }) it('throws w/ invalid OtherChainDestination', function () { tx.OtherChainDestination = 123 - assertInvalid(tx, 'XChainCommit: invalid field OtherChainDestination') + assertInvalid( + tx, + 'XChainCommit: invalid field OtherChainDestination, expected a valid account address', + ) }) it('throws w/ missing Amount', function () { @@ -78,6 +87,9 @@ describe('XChainCommit', function () { it('throws w/ invalid Amount', function () { tx.Amount = { currency: 'ETH' } - assertInvalid(tx, 'XChainCommit: invalid field Amount') + assertInvalid( + tx, + 'XChainCommit: invalid field Amount, expected a valid Amount', + ) }) }) diff --git a/packages/xrpl/test/models/XChainCreateBridge.test.ts b/packages/xrpl/test/models/XChainCreateBridge.test.ts index 740c92030d..7675eea5a7 100644 --- a/packages/xrpl/test/models/XChainCreateBridge.test.ts +++ b/packages/xrpl/test/models/XChainCreateBridge.test.ts @@ -49,7 +49,10 @@ describe('XChainCreateBridge', function () { it('throws w/ invalid XChainBridge', function () { tx.XChainBridge = { XChainDoor: 'test' } - assertInvalid(tx, 'XChainCreateBridge: invalid field XChainBridge') + assertInvalid( + tx, + 'XChainCreateBridge: invalid field XChainBridge, expected a valid XChainBridge object', + ) }) it('throws w/ missing SignatureReward', function () { @@ -61,7 +64,10 @@ describe('XChainCreateBridge', function () { it('throws w/ invalid SignatureReward', function () { tx.SignatureReward = { currency: 'ETH' } - assertInvalid(tx, 'XChainCreateBridge: invalid field SignatureReward') + assertInvalid( + tx, + 'XChainCreateBridge: invalid field SignatureReward, expected a valid Amount', + ) }) it('throws w/ invalid MinAccountCreateAmount', function () { @@ -69,7 +75,7 @@ describe('XChainCreateBridge', function () { assertInvalid( tx, - 'XChainCreateBridge: invalid field MinAccountCreateAmount', + 'XChainCreateBridge: invalid field MinAccountCreateAmount, expected a valid Amount', ) }) }) diff --git a/packages/xrpl/test/models/XChainCreateClaimID.test.ts b/packages/xrpl/test/models/XChainCreateClaimID.test.ts index 620e830954..2054c27bda 100644 --- a/packages/xrpl/test/models/XChainCreateClaimID.test.ts +++ b/packages/xrpl/test/models/XChainCreateClaimID.test.ts @@ -49,7 +49,10 @@ describe('XChainCreateClaimID', function () { it('throws w/ invalid XChainBridge', function () { tx.XChainBridge = { XChainDoor: 'test' } - assertInvalid(tx, 'XChainCreateClaimID: invalid field XChainBridge') + assertInvalid( + tx, + 'XChainCreateClaimID: invalid field XChainBridge, expected a valid XChainBridge object', + ) }) it('throws w/ missing SignatureReward', function () { @@ -61,7 +64,10 @@ describe('XChainCreateClaimID', function () { it('throws w/ invalid SignatureReward', function () { tx.SignatureReward = { currency: 'ETH' } - assertInvalid(tx, 'XChainCreateClaimID: invalid field SignatureReward') + assertInvalid( + tx, + 'XChainCreateClaimID: invalid field SignatureReward, expected a valid Amount', + ) }) it('throws w/ missing OtherChainSource', function () { @@ -73,6 +79,9 @@ describe('XChainCreateClaimID', function () { it('throws w/ invalid OtherChainSource', function () { tx.OtherChainSource = 123 - assertInvalid(tx, 'XChainCreateClaimID: invalid field OtherChainSource') + assertInvalid( + tx, + 'XChainCreateClaimID: invalid field OtherChainSource, expected a valid account address', + ) }) }) diff --git a/packages/xrpl/test/models/XChainModifyBridge.test.ts b/packages/xrpl/test/models/XChainModifyBridge.test.ts index 4ad095c999..3d6b6aec04 100644 --- a/packages/xrpl/test/models/XChainModifyBridge.test.ts +++ b/packages/xrpl/test/models/XChainModifyBridge.test.ts @@ -49,13 +49,19 @@ describe('XChainModifyBridge', function () { it('throws w/ invalid XChainBridge', function () { tx.XChainBridge = { XChainDoor: 'test' } - assertInvalid(tx, 'XChainModifyBridge: invalid field XChainBridge') + assertInvalid( + tx, + 'XChainModifyBridge: invalid field XChainBridge, expected a valid XChainBridge object', + ) }) it('throws w/ invalid SignatureReward', function () { tx.SignatureReward = { currency: 'ETH' } - assertInvalid(tx, 'XChainModifyBridge: invalid field SignatureReward') + assertInvalid( + tx, + 'XChainModifyBridge: invalid field SignatureReward, expected a valid Amount', + ) }) it('throws w/ invalid MinAccountCreateAmount', function () { @@ -63,7 +69,7 @@ describe('XChainModifyBridge', function () { assertInvalid( tx, - 'XChainModifyBridge: invalid field MinAccountCreateAmount', + 'XChainModifyBridge: invalid field MinAccountCreateAmount, expected a valid Amount', ) }) }) diff --git a/packages/xrpl/test/models/accountDelete.test.ts b/packages/xrpl/test/models/accountDelete.test.ts index d309706905..3d38f2e9b5 100644 --- a/packages/xrpl/test/models/accountDelete.test.ts +++ b/packages/xrpl/test/models/accountDelete.test.ts @@ -40,13 +40,15 @@ describe('AccountDelete', function () { it(`throws w/ invalid Destination`, function () { validAccountDelete.Destination = 65478965 - const errorMessage = 'AccountDelete: invalid field Destination' + const errorMessage = + 'AccountDelete: invalid field Destination, expected a valid account address' assertInvalid(validAccountDelete, errorMessage) }) it(`throws w/ invalid DestinationTag`, function () { validAccountDelete.DestinationTag = 'gvftyujnbv' - const errorMessage = 'AccountDelete: invalid field DestinationTag' + const errorMessage = + 'AccountDelete: invalid field DestinationTag, expected a valid number' assertInvalid(validAccountDelete, errorMessage) }) @@ -54,7 +56,8 @@ describe('AccountDelete', function () { validAccountDelete.CredentialIDs = 'EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F66A' - const errorMessage = 'AccountDelete: Credentials must be an array' + const errorMessage = + 'AccountDelete: invalid field CredentialIDs, expected a valid array' assertInvalid(validAccountDelete, errorMessage) }) @@ -72,14 +75,14 @@ describe('AccountDelete', function () { ] const errorMessage = - 'AccountDelete: Credentials length cannot exceed 8 elements' + 'AccountDelete: CredentialIDs length cannot exceed 8 elements' assertInvalid(validAccountDelete, errorMessage) }) it(`throws w/ empty CredentialIDs`, function () { validAccountDelete.CredentialIDs = [] - const errorMessage = 'AccountDelete: Credentials cannot be an empty array' + const errorMessage = 'AccountDelete: CredentialIDs cannot be an empty array' assertInvalid(validAccountDelete, errorMessage) }) @@ -89,7 +92,7 @@ describe('AccountDelete', function () { 'EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F662', ] - const errorMessage = 'AccountDelete: Invalid Credentials ID list format' + const errorMessage = 'AccountDelete: Invalid CredentialIDs list format' assertInvalid(validAccountDelete, errorMessage) }) @@ -100,7 +103,7 @@ describe('AccountDelete', function () { ] const errorMessage = - 'AccountDelete: Credentials cannot contain duplicate elements' + 'AccountDelete: CredentialIDs cannot contain duplicate elements' assertInvalid(validAccountDelete, errorMessage) }) }) diff --git a/packages/xrpl/test/models/accountSet.test.ts b/packages/xrpl/test/models/accountSet.test.ts index 7bd25952e4..f2de04105c 100644 --- a/packages/xrpl/test/models/accountSet.test.ts +++ b/packages/xrpl/test/models/accountSet.test.ts @@ -32,46 +32,67 @@ describe('AccountSet', function () { it(`throws w/ invalid SetFlag (out of range)`, function () { tx.SetFlag = 20 - assertInvalid(tx, 'AccountSet: invalid SetFlag') + assertInvalid(tx, 'AccountSet: invalid SetFlag value') }) it(`throws w/ invalid SetFlag (incorrect type)`, function () { tx.SetFlag = 'abc' - assertInvalid(tx, 'AccountSet: invalid SetFlag') + assertInvalid( + tx, + 'AccountSet: invalid field SetFlag, expected a valid number', + ) }) it(`throws w/ invalid ClearFlag`, function () { tx.ClearFlag = 20 - assertInvalid(tx, 'AccountSet: invalid ClearFlag') + assertInvalid(tx, 'AccountSet: invalid ClearFlag value') }) it(`throws w/ invalid Domain`, function () { tx.Domain = 6578616 - assertInvalid(tx, 'AccountSet: invalid Domain') + assertInvalid( + tx, + 'AccountSet: invalid field Domain, expected a valid hex string', + ) }) it(`throws w/ invalid EmailHash`, function () { tx.EmailHash = 6578656789876543 - assertInvalid(tx, 'AccountSet: invalid EmailHash') + assertInvalid( + tx, + 'AccountSet: invalid field EmailHash, expected a valid hex string', + ) }) it(`throws w/ invalid MessageKey`, function () { tx.MessageKey = 6578656789876543 - assertInvalid(tx, 'AccountSet: invalid MessageKey') + assertInvalid( + tx, + 'AccountSet: invalid field MessageKey, expected a valid hex string', + ) }) it(`throws w/ invalid TransferRate`, function () { - tx.TransferRate = '1000000001' - assertInvalid(tx, 'AccountSet: invalid TransferRate') + tx.TransferRate = 'abcd' + assertInvalid( + tx, + 'AccountSet: invalid field TransferRate, expected a valid number', + ) }) it(`throws w/ invalid TickSize`, function () { tx.TickSize = 20 - assertInvalid(tx, 'AccountSet: invalid TickSize') + assertInvalid( + tx, + 'AccountSet: invalid field TickSize, expected a valid number', + ) }) it(`throws w/ invalid NFTokenMinter`, function () { tx.NFTokenMinter = '' - assertInvalid(tx, 'AccountSet: invalid field NFTokenMinter') + assertInvalid( + tx, + 'AccountSet: invalid field NFTokenMinter, expected a valid account address', + ) }) }) diff --git a/packages/xrpl/test/models/baseTransaction.test.ts b/packages/xrpl/test/models/baseTransaction.test.ts index 0d85f44a33..2c2111d3a1 100644 --- a/packages/xrpl/test/models/baseTransaction.test.ts +++ b/packages/xrpl/test/models/baseTransaction.test.ts @@ -5,8 +5,14 @@ import { validateBaseTransaction } from '../../src/models/transactions/common' const assertValid = (tx: any): void => assert.doesNotThrow(() => validateBaseTransaction(tx)) -const assertInvalid = (tx: any, message: string): void => - assert.throws(() => validateBaseTransaction(tx), ValidationError, message) +const assertInvalid = (tx: any, message: string): void => { + assert.throws( + () => validateBaseTransaction(tx), + ValidationError, + // eslint-disable-next-line require-unicode-regexp -- TS complains if it's included + new RegExp(`^${message.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'u'), + ) +} /** * Transaction Verification Testing. @@ -60,7 +66,15 @@ describe('BaseTransaction', function () { TxnSignature: '3045022100C6708538AE5A697895937C758E99A595B57A16393F370F11B8D4C032E80B532002207776A8E85BB9FAF460A92113B9C60F170CD964196B1F084E0DAB65BAEC368B66', } + assertValid(txJson) + }) + it('Verifies flag map', function () { + const txJson = { + Account: 'r97KeayHuEsDwyU1yPBVtMLLoQr79QcRFe', + TransactionType: 'Payment', + Flags: { tfNoRippleDirect: true }, + } assertValid(txJson) }) @@ -80,17 +94,23 @@ describe('BaseTransaction', function () { Fee: 1000, } as any - assertInvalid(invalidFee, 'Payment: invalid field Fee') + assertInvalid( + invalidFee, + 'Payment: invalid field Fee, expected a valid XRP Amount', + ) }) it(`Handles invalid Sequence`, function () { const invalidSeq = { Account: 'r97KeayHuEsDwyU1yPBVtMLLoQr79QcRFe', TransactionType: 'Payment', - Sequence: '145', + Sequence: 'abcd', } as any - assertInvalid(invalidSeq, 'Payment: invalid field Sequence') + assertInvalid( + invalidSeq, + 'Payment: invalid field Sequence, expected a valid number', + ) }) it(`Handles invalid AccountTxnID`, function () { @@ -100,19 +120,22 @@ describe('BaseTransaction', function () { AccountTxnID: ['WRONG'], } as any - assertInvalid(invalidID, 'Payment: invalid field AccountTxnID') + assertInvalid( + invalidID, + 'Payment: invalid field AccountTxnID, expected a valid hex string', + ) }) it(`Handles invalid LastLedgerSequence`, function () { const invalidLastLedgerSequence = { Account: 'r97KeayHuEsDwyU1yPBVtMLLoQr79QcRFe', TransactionType: 'Payment', - LastLedgerSequence: '1000', + LastLedgerSequence: 'abcd', } as any assertInvalid( invalidLastLedgerSequence, - 'Payment: invalid field LastLedgerSequence', + 'Payment: invalid field LastLedgerSequence, expected a valid number', ) }) @@ -123,7 +146,23 @@ describe('BaseTransaction', function () { SourceTag: ['ARRAY'], } as any - assertInvalid(invalidSourceTag, 'Payment: invalid field SourceTag') + assertInvalid( + invalidSourceTag, + 'Payment: invalid field SourceTag, expected a valid number', + ) + }) + + it(`Handles invalid Flags`, function () { + const invalidFlags = { + Account: 'r97KeayHuEsDwyU1yPBVtMLLoQr79QcRFe', + TransactionType: 'Payment', + Flags: 'abcd', + } as any + + assertInvalid( + invalidFlags, + 'Payment: invalid field Flags, expected a valid number or Flags object', + ) }) it(`Handles invalid SigningPubKey`, function () { @@ -133,19 +172,22 @@ describe('BaseTransaction', function () { SigningPubKey: 1000, } as any - assertInvalid(invalidSigningPubKey, 'Payment: invalid field SigningPubKey') + assertInvalid( + invalidSigningPubKey, + 'Payment: invalid field SigningPubKey, expected a valid hex string', + ) }) it(`Handles invalid TicketSequence`, function () { const invalidTicketSequence = { Account: 'r97KeayHuEsDwyU1yPBVtMLLoQr79QcRFe', TransactionType: 'Payment', - TicketSequence: '1000', + TicketSequence: 'abcd', } as any assertInvalid( invalidTicketSequence, - 'Payment: invalid field TicketSequence', + 'Payment: invalid field TicketSequence, expected a valid number', ) }) @@ -156,7 +198,10 @@ describe('BaseTransaction', function () { TxnSignature: 1000, } as any - assertInvalid(invalidTxnSignature, 'Payment: invalid field TxnSignature') + assertInvalid( + invalidTxnSignature, + 'Payment: invalid field TxnSignature, expected a valid hex string', + ) }) it(`Handles invalid Signers`, function () { @@ -166,7 +211,7 @@ describe('BaseTransaction', function () { Signers: [], } as any - assertInvalid(invalidSigners, 'BaseTransaction: invalid Signers') + assertInvalid(invalidSigners, 'BaseTransaction: invalid field Signers') const invalidSigners2 = { Account: 'r97KeayHuEsDwyU1yPBVtMLLoQr79QcRFe', @@ -180,7 +225,7 @@ describe('BaseTransaction', function () { ], } as any - assertInvalid(invalidSigners2, 'BaseTransaction: invalid Signers') + assertInvalid(invalidSigners2, 'BaseTransaction: invalid field Signers') }) it(`Handles invalid Memo`, function () { @@ -197,16 +242,19 @@ describe('BaseTransaction', function () { ], } as any - assertInvalid(invalidMemo, 'BaseTransaction: invalid Memos') + assertInvalid(invalidMemo, 'BaseTransaction: invalid field Memos') }) it(`Handles invalid NetworkID`, function () { const invalidNetworkID = { Account: 'r97KeayHuEsDwyU1yPBVtMLLoQr79QcRFe', TransactionType: 'Payment', - NetworkID: '1024', + NetworkID: 'abcd', } - assertInvalid(invalidNetworkID, 'Payment: invalid field NetworkID') + assertInvalid( + invalidNetworkID, + 'Payment: invalid field NetworkID, expected a valid number', + ) }) it(`Handles invalid Delegate`, function () { @@ -215,7 +263,10 @@ describe('BaseTransaction', function () { TransactionType: 'Payment', Delegate: 1234, } - assertInvalid(invalidDelegate, 'Payment: invalid field Delegate') + assertInvalid( + invalidDelegate, + 'Payment: invalid field Delegate, expected a valid account address', + ) }) it(`Handles Account and Delegate being the same error`, function () { diff --git a/packages/xrpl/test/models/batch.test.ts b/packages/xrpl/test/models/batch.test.ts index 25e386c8cc..82607c702d 100644 --- a/packages/xrpl/test/models/batch.test.ts +++ b/packages/xrpl/test/models/batch.test.ts @@ -103,7 +103,10 @@ describe('Batch', function () { it('throws w/ invalid BatchSigners', function () { tx.BatchSigners = 0 - assertInvalid(tx, 'Batch: invalid field BatchSigners') + assertInvalid( + tx, + 'Batch: invalid field BatchSigners, expected a valid array', + ) }) it('throws w/ missing RawTransactions', function () { @@ -113,17 +116,26 @@ describe('Batch', function () { it('throws w/ invalid RawTransactions', function () { tx.RawTransactions = 0 - assertInvalid(tx, 'Batch: invalid field RawTransactions') + assertInvalid( + tx, + 'Batch: invalid field RawTransactions, expected a valid array', + ) }) it('throws w/ invalid RawTransactions object', function () { tx.RawTransactions = [0] - assertInvalid(tx, 'Batch: RawTransactions[0] is not object') + assertInvalid( + tx, + 'Batch: invalid field RawTransactions[0], expected a valid Record', + ) }) it('throws w/ invalid RawTransactions.RawTransaction object', function () { tx.RawTransactions = [{ RawTransaction: 0 }] - assertInvalid(tx, 'Batch: invalid field RawTransactions[0].RawTransaction') + assertInvalid( + tx, + 'Batch: invalid field RawTransactions[0].RawTransaction, expected a valid Record', + ) }) it('throws w/ nested Batch', function () { diff --git a/packages/xrpl/test/models/checkCancel.test.ts b/packages/xrpl/test/models/checkCancel.test.ts index ed180d5629..2950f3292e 100644 --- a/packages/xrpl/test/models/checkCancel.test.ts +++ b/packages/xrpl/test/models/checkCancel.test.ts @@ -29,6 +29,9 @@ describe('CheckCancel', function () { CheckID: 4964734566545678, } as any - assertInvalid(invalidCheckID, 'CheckCancel: invalid CheckID') + assertInvalid( + invalidCheckID, + 'CheckCancel: invalid field CheckID, expected a valid hex string', + ) }) }) diff --git a/packages/xrpl/test/models/checkCash.test.ts b/packages/xrpl/test/models/checkCash.test.ts index 401cd0df18..6c07dd4e1e 100644 --- a/packages/xrpl/test/models/checkCash.test.ts +++ b/packages/xrpl/test/models/checkCash.test.ts @@ -32,7 +32,10 @@ describe('CheckCash', function () { CheckID: 83876645678567890, } as any - assertInvalid(invalidCheckID, 'CheckCash: invalid CheckID') + assertInvalid( + invalidCheckID, + 'CheckCash: invalid field CheckID, expected a valid hex string', + ) }) it(`throws w/ invalid Amount`, function () { @@ -44,7 +47,10 @@ describe('CheckCash', function () { '838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334', } as any - assertInvalid(invalidAmount, 'CheckCash: invalid Amount') + assertInvalid( + invalidAmount, + 'CheckCash: invalid field Amount, expected a valid Amount', + ) }) it(`throws w/ having both Amount and DeliverMin`, function () { @@ -52,7 +58,7 @@ describe('CheckCash', function () { Account: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy', TransactionType: 'CheckCash', Amount: '100000000', - DeliverMin: 852156963, + DeliverMin: '852156963', CheckID: '838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334', } as any @@ -72,6 +78,9 @@ describe('CheckCash', function () { '838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334', } as any - assertInvalid(invalidDeliverMin, 'CheckCash: invalid DeliverMin') + assertInvalid( + invalidDeliverMin, + 'CheckCash: invalid field DeliverMin, expected a valid Amount', + ) }) }) diff --git a/packages/xrpl/test/models/checkCreate.test.ts b/packages/xrpl/test/models/checkCreate.test.ts index 812973705f..69347590e6 100644 --- a/packages/xrpl/test/models/checkCreate.test.ts +++ b/packages/xrpl/test/models/checkCreate.test.ts @@ -40,7 +40,10 @@ describe('CheckCreate', function () { Fee: '12', } as any - assertInvalid(invalidDestination, 'CheckCreate: invalid field Destination') + assertInvalid( + invalidDestination, + 'CheckCreate: invalid field Destination, expected a valid account address', + ) }) it(`throws w/ invalid SendMax`, function () { @@ -56,7 +59,10 @@ describe('CheckCreate', function () { Fee: '12', } as any - assertInvalid(invalidSendMax, 'CheckCreate: invalid SendMax') + assertInvalid( + invalidSendMax, + 'CheckCreate: invalid field SendMax, expected a valid Amount', + ) }) it(`throws w/ invalid DestinationTag`, function () { @@ -68,13 +74,13 @@ describe('CheckCreate', function () { Expiration: 570113521, InvoiceID: '6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B', - DestinationTag: '1', + DestinationTag: 'abcd', Fee: '12', } as any assertInvalid( invalidDestinationTag, - 'CheckCreate: invalid field DestinationTag', + 'CheckCreate: invalid field DestinationTag, expected a valid number', ) }) @@ -84,14 +90,17 @@ describe('CheckCreate', function () { Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo', Destination: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy', SendMax: '100000000', - Expiration: '570113521', + Expiration: 'abcd', InvoiceID: '6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B', DestinationTag: 1, Fee: '12', } as any - assertInvalid(invalidExpiration, 'CheckCreate: invalid Expiration') + assertInvalid( + invalidExpiration, + 'CheckCreate: invalid field Expiration, expected a valid number', + ) }) it(`throws w/ invalid InvoiceID`, function () { @@ -106,6 +115,9 @@ describe('CheckCreate', function () { Fee: '12', } as any - assertInvalid(invalidInvoiceID, 'CheckCreate: invalid InvoiceID') + assertInvalid( + invalidInvoiceID, + 'CheckCreate: invalid field InvoiceID, expected a valid hex string', + ) }) }) diff --git a/packages/xrpl/test/models/clawback.test.ts b/packages/xrpl/test/models/clawback.test.ts index c957b6a916..9aae4ca623 100644 --- a/packages/xrpl/test/models/clawback.test.ts +++ b/packages/xrpl/test/models/clawback.test.ts @@ -41,7 +41,10 @@ describe('Clawback', function () { Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm', } as any - assertInvalid(invalidAmount, 'Clawback: invalid field Amount') + assertInvalid( + invalidAmount, + 'Clawback: invalid field Amount, expected a valid non-XRP Amount', + ) const invalidStrAmount = { TransactionType: 'Clawback', @@ -49,7 +52,10 @@ describe('Clawback', function () { Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm', } as any - assertInvalid(invalidStrAmount, 'Clawback: invalid field Amount') + assertInvalid( + invalidStrAmount, + 'Clawback: invalid field Amount, expected a valid non-XRP Amount', + ) }) it(`throws w/ invalid holder Account`, function () { @@ -63,7 +69,10 @@ describe('Clawback', function () { Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm', } as any - assertInvalid(invalidAccount, 'Clawback: invalid holder Account') + assertInvalid( + invalidAccount, + 'Clawback: Amount.issuer and Account cannot be the same', + ) }) it(`verifies valid MPT Clawback`, function () { @@ -91,7 +100,10 @@ describe('Clawback', function () { Holder: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm', } as any - assertInvalid(invalidAccount, 'Clawback: invalid holder Account') + assertInvalid( + invalidAccount, + 'Clawback: Account and Holder cannot be the same', + ) }) it(`throws w/ invalid Holder`, function () { @@ -104,7 +116,7 @@ describe('Clawback', function () { Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm', } as any - assertInvalid(invalidAccount, 'Clawback: missing Holder') + assertInvalid(invalidAccount, 'Clawback: missing field Holder') }) it(`throws w/ invalid currency Holder`, function () { diff --git a/packages/xrpl/test/models/delegateSet.test.ts b/packages/xrpl/test/models/delegateSet.test.ts index 5b9cbb3dff..1349156dec 100644 --- a/packages/xrpl/test/models/delegateSet.test.ts +++ b/packages/xrpl/test/models/delegateSet.test.ts @@ -49,7 +49,8 @@ describe('DelegateSet', function () { it(`throws w/ invalid field Permissions`, function () { tx.Permissions = 'TrustlineAuthorize' - const errorMessage = 'DelegateSet: invalid field Permissions' + const errorMessage = + 'DelegateSet: invalid field Permissions, expected a valid array' assertInvalid(tx, errorMessage) }) @@ -80,27 +81,29 @@ describe('DelegateSet', function () { it(`throws w/ PermissionValue must be defined`, function () { tx.Permissions = [{ Permission: { PermissionValue: null } }] - const errorMessage = 'DelegateSet: PermissionValue must be defined' + const errorMessage = + 'DelegateSet: missing field Permission[0].PermissionValue' assertInvalid(tx, errorMessage) }) it(`throws w/ PermissionValue must be a string`, function () { tx.Permissions = [{ Permission: { PermissionValue: 123 } }] - const errorMessage = 'DelegateSet: PermissionValue must be a string' + const errorMessage = + 'DelegateSet: invalid field Permission[0].PermissionValue, expected a valid string' assertInvalid(tx, errorMessage) }) - it(`throws w/ PermissionValue contains a non-delegatable transaction`, function () { + it(`throws w/ PermissionValue contains a non-delegable transaction`, function () { tx.Permissions = [{ Permission: { PermissionValue: 'AccountSet' } }] const errorMessage = - 'DelegateSet: PermissionValue contains a non-delegatable transaction AccountSet' + 'DelegateSet: PermissionValue contains non-delegable transaction AccountSet' assertInvalid(tx, errorMessage) }) - it(`throws w/ PermissionValue contains a non-delegatable pseudo transaction`, function () { + it(`throws w/ PermissionValue contains a non-delegable pseudo transaction`, function () { tx.Permissions = [{ Permission: { PermissionValue: 'EnableAmendment' } }] const errorMessage = - 'DelegateSet: PermissionValue contains a non-delegatable transaction EnableAmendment' + 'DelegateSet: PermissionValue contains non-delegable transaction EnableAmendment' assertInvalid(tx, errorMessage) }) diff --git a/packages/xrpl/test/models/depositPreauth.test.ts b/packages/xrpl/test/models/depositPreauth.test.ts index 01737f8a59..a4185d30fb 100644 --- a/packages/xrpl/test/models/depositPreauth.test.ts +++ b/packages/xrpl/test/models/depositPreauth.test.ts @@ -80,7 +80,10 @@ describe('DepositPreauth', function () { it('throws when Authorize is not a string', function () { depositPreauth.Authorize = 1234 - assertInvalid(depositPreauth, 'DepositPreauth: Authorize must be a string') + assertInvalid( + depositPreauth, + 'DepositPreauth: invalid field Authorize, expected a valid account address', + ) }) it('throws when an Account attempts to preauthorize its own address', function () { @@ -95,7 +98,7 @@ describe('DepositPreauth', function () { depositPreauth.Unauthorize = 1234 assertInvalid( depositPreauth, - 'DepositPreauth: Unauthorize must be a string', + 'DepositPreauth: invalid field Unauthorize, expected a valid account address', ) }) @@ -108,28 +111,32 @@ describe('DepositPreauth', function () { }) it('throws when AuthorizeCredentials is not an array', function () { - const errorMessage = 'DepositPreauth: Credentials must be an array' + const errorMessage = + 'DepositPreauth: invalid field AuthorizeCredentials, expected a valid array' depositPreauth.AuthorizeCredentials = validCredential assertInvalid(depositPreauth, errorMessage) }) it('throws when UnauthorizeCredentials is not an array', function () { - const errorMessage = 'DepositPreauth: Credentials must be an array' + const errorMessage = + 'DepositPreauth: invalid field UnauthorizeCredentials, expected a valid array' depositPreauth.UnauthorizeCredentials = validCredential assertInvalid(depositPreauth, errorMessage) }) it('throws when AuthorizeCredentials is empty array', function () { - const errorMessage = 'DepositPreauth: Credentials cannot be an empty array' + const errorMessage = + 'DepositPreauth: AuthorizeCredentials cannot be an empty array' depositPreauth.AuthorizeCredentials = [] assertInvalid(depositPreauth, errorMessage) }) it('throws when UnauthorizeCredentials is empty array', function () { - const errorMessage = 'DepositPreauth: Credentials cannot be an empty array' + const errorMessage = + 'DepositPreauth: UnauthorizeCredentials cannot be an empty array' depositPreauth.UnauthorizeCredentials = [] assertInvalid(depositPreauth, errorMessage) @@ -138,7 +145,7 @@ describe('DepositPreauth', function () { it('throws when AuthorizeCredentials is too long', function () { const sampleCredentials: AuthorizeCredential[] = [] const errorMessage = - 'DepositPreauth: Credentials length cannot exceed 8 elements' + 'DepositPreauth: AuthorizeCredentials length cannot exceed 8 elements' for (let index = 0; index < 9; index++) { sampleCredentials.push({ Credential: { @@ -154,7 +161,7 @@ describe('DepositPreauth', function () { it('throws when UnauthorizeCredentials is too long', function () { const sampleCredentials: AuthorizeCredential[] = [] const errorMessage = - 'DepositPreauth: Credentials length cannot exceed 8 elements' + 'DepositPreauth: UnauthorizeCredentials length cannot exceed 8 elements' for (let index = 0; index < 9; index++) { sampleCredentials.push({ Credential: { @@ -172,7 +179,7 @@ describe('DepositPreauth', function () { { Credential: 'Invalid Shape' }, { Credential: 'Another Invalid Shape' }, ] - const errorMessage = 'DepositPreauth: Invalid Credentials format' + const errorMessage = 'DepositPreauth: Invalid AuthorizeCredentials format' depositPreauth.AuthorizeCredentials = invalidCredentials assertInvalid(depositPreauth, errorMessage) @@ -183,7 +190,7 @@ describe('DepositPreauth', function () { { Credential: 'Invalid Shape' }, { Credential: 'Another Invalid Shape' }, ] - const errorMessage = 'DepositPreauth: Invalid Credentials format' + const errorMessage = 'DepositPreauth: Invalid UnauthorizeCredentials format' depositPreauth.UnauthorizeCredentials = invalidCredentials assertInvalid(depositPreauth, errorMessage) @@ -192,7 +199,7 @@ describe('DepositPreauth', function () { it('throws when AuthorizeCredentials has duplicates', function () { const invalidCredentials = [validCredential, validCredential] const errorMessage = - 'DepositPreauth: Credentials cannot contain duplicate elements' + 'DepositPreauth: AuthorizeCredentials cannot contain duplicate elements' depositPreauth.AuthorizeCredentials = invalidCredentials assertInvalid(depositPreauth, errorMessage) @@ -201,7 +208,7 @@ describe('DepositPreauth', function () { it('throws when UnauthorizeCredentials has duplicates', function () { const invalidCredentials = [validCredential, validCredential] const errorMessage = - 'DepositPreauth: Credentials cannot contain duplicate elements' + 'DepositPreauth: UnauthorizeCredentials cannot contain duplicate elements' depositPreauth.UnauthorizeCredentials = invalidCredentials assertInvalid(depositPreauth, errorMessage) diff --git a/packages/xrpl/test/models/escrowCancel.test.ts b/packages/xrpl/test/models/escrowCancel.test.ts index 1a679c77b0..d3d502c893 100644 --- a/packages/xrpl/test/models/escrowCancel.test.ts +++ b/packages/xrpl/test/models/escrowCancel.test.ts @@ -41,18 +41,24 @@ describe('EscrowCancel', function () { it(`Invalid EscrowCancel missing offerSequence`, function () { delete cancel.OfferSequence - assertInvalid(cancel, 'EscrowCancel: missing OfferSequence') + assertInvalid(cancel, 'EscrowCancel: missing field OfferSequence') }) it(`Invalid Owner`, function () { cancel.Owner = 10 - assertInvalid(cancel, 'EscrowCancel: invalid field Owner') + assertInvalid( + cancel, + 'EscrowCancel: invalid field Owner, expected a valid account address', + ) }) it(`Invalid OfferSequence`, function () { cancel.OfferSequence = 'random' - assertInvalid(cancel, 'EscrowCancel: OfferSequence must be a number') + assertInvalid( + cancel, + 'EscrowCancel: invalid field OfferSequence, expected a valid number', + ) }) }) diff --git a/packages/xrpl/test/models/escrowCreate.test.ts b/packages/xrpl/test/models/escrowCreate.test.ts index bb0d4e207b..d5cac0e912 100644 --- a/packages/xrpl/test/models/escrowCreate.test.ts +++ b/packages/xrpl/test/models/escrowCreate.test.ts @@ -47,37 +47,55 @@ describe('EscrowCreate', function () { it(`throws w/ invalid Destination`, function () { escrow.Destination = 10 - assertInvalid(escrow, 'EscrowCreate: invalid field Destination') + assertInvalid( + escrow, + 'EscrowCreate: invalid field Destination, expected a valid account address', + ) }) it(`throws w/ invalid Amount`, function () { escrow.Amount = 1000 - assertInvalid(escrow, 'EscrowCreate: invalid field Amount') + assertInvalid( + escrow, + 'EscrowCreate: invalid field Amount, expected a valid Amount', + ) }) it(`invalid CancelAfter`, function () { - escrow.CancelAfter = '100' + escrow.CancelAfter = 'abcd' - assertInvalid(escrow, 'EscrowCreate: CancelAfter must be a number') + assertInvalid( + escrow, + 'EscrowCreate: invalid field CancelAfter, expected a valid number', + ) }) it(`invalid FinishAfter`, function () { - escrow.FinishAfter = '1000' + escrow.FinishAfter = 'abcd' - assertInvalid(escrow, 'EscrowCreate: FinishAfter must be a number') + assertInvalid( + escrow, + 'EscrowCreate: invalid field FinishAfter, expected a valid number', + ) }) it(`invalid Condition`, function () { escrow.Condition = 0x141243 - assertInvalid(escrow, 'EscrowCreate: Condition must be a string') + assertInvalid( + escrow, + 'EscrowCreate: invalid field Condition, expected a valid hex string', + ) }) it(`invalid DestinationTag`, function () { - escrow.DestinationTag = '100' + escrow.DestinationTag = 'abcd' - assertInvalid(escrow, 'EscrowCreate: invalid field DestinationTag') + assertInvalid( + escrow, + 'EscrowCreate: invalid field DestinationTag, expected a valid number', + ) }) it(`Missing both CancelAfter and FinishAfter`, function () { diff --git a/packages/xrpl/test/models/escrowFinish.test.ts b/packages/xrpl/test/models/escrowFinish.test.ts index 252858315e..6461047ff5 100644 --- a/packages/xrpl/test/models/escrowFinish.test.ts +++ b/packages/xrpl/test/models/escrowFinish.test.ts @@ -48,32 +48,45 @@ describe('EscrowFinish', function () { it(`throws w/ invalid Owner`, function () { escrow.Owner = 0x15415253 - assertInvalid(escrow, 'EscrowFinish: invalid field Owner') + assertInvalid( + escrow, + 'EscrowFinish: invalid field Owner, expected a valid account address', + ) }) it(`throws w/ invalid OfferSequence`, function () { escrow.OfferSequence = 'random' - assertInvalid(escrow, 'EscrowFinish: OfferSequence must be a number') + assertInvalid( + escrow, + 'EscrowFinish: invalid field OfferSequence, expected a valid number', + ) }) it(`throws w/ invalid Condition`, function () { escrow.Condition = 10 - assertInvalid(escrow, 'EscrowFinish: Condition must be a string') + assertInvalid( + escrow, + 'EscrowFinish: invalid field Condition, expected a valid hex string', + ) }) it(`throws w/ invalid Fulfillment`, function () { escrow.Fulfillment = 0x142341 - assertInvalid(escrow, 'EscrowFinish: Fulfillment must be a string') + assertInvalid( + escrow, + 'EscrowFinish: invalid field Fulfillment, expected a valid hex string', + ) }) it(`throws w/ non-array CredentialIDs`, function () { escrow.CredentialIDs = 'EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F66A' - const errorMessage = 'EscrowFinish: Credentials must be an array' + const errorMessage = + 'EscrowFinish: invalid field CredentialIDs, expected a valid array' assertInvalid(escrow, errorMessage) }) @@ -92,7 +105,7 @@ describe('EscrowFinish', function () { ] const errorMessage = - 'EscrowFinish: Credentials length cannot exceed 8 elements' + 'EscrowFinish: CredentialIDs length cannot exceed 8 elements' assertInvalid(escrow, errorMessage) }) @@ -100,7 +113,7 @@ describe('EscrowFinish', function () { it(`throws w/ empty CredentialIDs`, function () { escrow.CredentialIDs = [] - const errorMessage = 'EscrowFinish: Credentials cannot be an empty array' + const errorMessage = 'EscrowFinish: CredentialIDs cannot be an empty array' assertInvalid(escrow, errorMessage) }) @@ -111,7 +124,7 @@ describe('EscrowFinish', function () { 'EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F662', ] - const errorMessage = 'EscrowFinish: Invalid Credentials ID list format' + const errorMessage = 'EscrowFinish: Invalid CredentialIDs list format' assertInvalid(escrow, errorMessage) }) @@ -123,7 +136,7 @@ describe('EscrowFinish', function () { ] const errorMessage = - 'EscrowFinish: Credentials cannot contain duplicate elements' + 'EscrowFinish: CredentialIDs cannot contain duplicate elements' assertInvalid(escrow, errorMessage) }) diff --git a/packages/xrpl/test/models/loanBrokerCoverDeposit.test.ts b/packages/xrpl/test/models/loanBrokerCoverDeposit.test.ts index fac3bcc802..dc2e2a244e 100644 --- a/packages/xrpl/test/models/loanBrokerCoverDeposit.test.ts +++ b/packages/xrpl/test/models/loanBrokerCoverDeposit.test.ts @@ -43,7 +43,10 @@ describe('unit test LoanBrokerCoverDeposit', () => { mpt_issuanceId: '0000012FFD9EE5DA93AC614B4DB94D7E0FCE415CA51BED47', value: '1000000', } - assertInvalid(tx, 'LoanBrokerCoverDeposit: invalid field Amount') + assertInvalid( + tx, + 'LoanBrokerCoverDeposit: invalid field Amount, expected a valid Amount', + ) delete tx.Amount assertInvalid(tx, 'LoanBrokerCoverDeposit: missing field Amount') diff --git a/packages/xrpl/test/models/loanBrokerCoverWithdraw.test.ts b/packages/xrpl/test/models/loanBrokerCoverWithdraw.test.ts index 5e82d972f9..d1d4045349 100644 --- a/packages/xrpl/test/models/loanBrokerCoverWithdraw.test.ts +++ b/packages/xrpl/test/models/loanBrokerCoverWithdraw.test.ts @@ -44,7 +44,10 @@ describe('unit test LoanBrokerCoverWithdraw', () => { mpt_issuanceId: '0000012FFD9EE5DA93AC614B4DB94D7E0FCE415CA51BED47', value: '1000000', } - assertInvalid(tx, 'LoanBrokerCoverWithdraw: invalid field Amount') + assertInvalid( + tx, + 'LoanBrokerCoverWithdraw: invalid field Amount, expected a valid Amount', + ) delete tx.Amount assertInvalid(tx, 'LoanBrokerCoverWithdraw: missing field Amount') diff --git a/packages/xrpl/test/models/loanPay.test.ts b/packages/xrpl/test/models/loanPay.test.ts index 897269d220..52afe9fc3b 100644 --- a/packages/xrpl/test/models/loanPay.test.ts +++ b/packages/xrpl/test/models/loanPay.test.ts @@ -81,6 +81,6 @@ describe('unit test LoanPay', () => { test('invalid Amount', () => { tx.Amount = 123 - assertInvalid(tx, 'LoanPay: invalid field Amount') + assertInvalid(tx, 'LoanPay: invalid field Amount, expected a valid Amount') }) }) diff --git a/packages/xrpl/test/models/offerCancel.test.ts b/packages/xrpl/test/models/offerCancel.test.ts index 3d1c91b971..ec7811e439 100644 --- a/packages/xrpl/test/models/offerCancel.test.ts +++ b/packages/xrpl/test/models/offerCancel.test.ts @@ -40,7 +40,10 @@ describe('OfferCancel', function () { it(`throws w/ OfferSequence must be a number`, function () { offer.OfferSequence = 'abcd' - assertInvalid(offer, 'OfferCancel: OfferSequence must be a number') + assertInvalid( + offer, + 'OfferCancel: invalid field OfferSequence, expected a valid number', + ) }) it(`throws w/ missing OfferSequence`, function () { diff --git a/packages/xrpl/test/models/offerCreate.test.ts b/packages/xrpl/test/models/offerCreate.test.ts index 035891b6bb..f9002f646b 100644 --- a/packages/xrpl/test/models/offerCreate.test.ts +++ b/packages/xrpl/test/models/offerCreate.test.ts @@ -14,8 +14,10 @@ const assertInvalid = (tx: any, message: string): void => * Providing runtime verification testing for each specific transaction type. */ describe('OfferCreate', function () { - it(`verifies valid OfferCreate`, function () { - const offerTx = { + let offer: any + + beforeEach(function () { + offer = { Account: 'r3rhWeE31Jt5sWmi4QiGLMZnY3ENgqw96W', Fee: '10', Flags: 0, @@ -34,9 +36,11 @@ describe('OfferCreate', function () { TransactionType: 'OfferCreate', TxnSignature: '3045022100D874CDDD6BB24ED66E83B1D3574D3ECAC753A78F26DB7EBA89EAB8E7D72B95F802207C8CCD6CEA64E4AE2014E59EE9654E02CA8F03FE7FCE0539E958EAE182234D91', - } + } as any + }) - assertValid(offerTx) + it(`verifies valid OfferCreate`, function () { + assertValid(offer) }) it(`verifies valid OfferCreate with flags`, function () { @@ -195,94 +199,38 @@ describe('OfferCreate', function () { }) it(`throws w/ invalid Expiration`, function () { - const offerTx = { - Account: 'r3rhWeE31Jt5sWmi4QiGLMZnY3ENgqw96W', - Fee: '10', - Flags: 0, - LastLedgerSequence: 65453019, - Sequence: 40949322, - SigningPubKey: - '03C48299E57F5AE7C2BE1391B581D313F1967EA2301628C07AC412092FDC15BA22', - Expiration: '11', - TakerGets: '12928290425', - TakerPays: { - currency: 'DSH', - issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX', - value: '43.11584856965009', - }, - TransactionType: 'OfferCreate', - TxnSignature: - '3045022100D874CDDD6BB24ED66E83B1D3574D3ECAC753A78F26DB7EBA89EAB8E7D72B95F802207C8CCD6CEA64E4AE2014E59EE9654E02CA8F03FE7FCE0539E958EAE182234D91', - } as any + offer.Expiration = 'abcd' - assertInvalid(offerTx, 'OfferCreate: invalid Expiration') + assertInvalid( + offer, + 'OfferCreate: invalid field Expiration, expected a valid number', + ) }) it(`throws w/ invalid OfferSequence`, function () { - const offerTx = { - Account: 'r3rhWeE31Jt5sWmi4QiGLMZnY3ENgqw96W', - Fee: '10', - Flags: 0, - LastLedgerSequence: 65453019, - Sequence: 40949322, - SigningPubKey: - '03C48299E57F5AE7C2BE1391B581D313F1967EA2301628C07AC412092FDC15BA22', - OfferSequence: '11', - TakerGets: '12928290425', - TakerPays: { - currency: 'DSH', - issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX', - value: '43.11584856965009', - }, - TransactionType: 'OfferCreate', - TxnSignature: - '3045022100D874CDDD6BB24ED66E83B1D3574D3ECAC753A78F26DB7EBA89EAB8E7D72B95F802207C8CCD6CEA64E4AE2014E59EE9654E02CA8F03FE7FCE0539E958EAE182234D91', - } as any + offer.OfferSequence = 'abcd' - assertInvalid(offerTx, 'OfferCreate: invalid OfferSequence') + assertInvalid( + offer, + 'OfferCreate: invalid field OfferSequence, expected a valid number', + ) }) it(`throws w/ invalid TakerPays`, function () { - const offerTx = { - Account: 'r3rhWeE31Jt5sWmi4QiGLMZnY3ENgqw96W', - Fee: '10', - Flags: 0, - LastLedgerSequence: 65453019, - Sequence: 40949322, - SigningPubKey: - '03C48299E57F5AE7C2BE1391B581D313F1967EA2301628C07AC412092FDC15BA22', - OfferSequence: '11', - TakerGets: '12928290425', - TakerPays: 10, - TransactionType: 'OfferCreate', - TxnSignature: - '3045022100D874CDDD6BB24ED66E83B1D3574D3ECAC753A78F26DB7EBA89EAB8E7D72B95F802207C8CCD6CEA64E4AE2014E59EE9654E02CA8F03FE7FCE0539E958EAE182234D91', - } as any + offer.TakerPays = 10 - assertInvalid(offerTx, 'OfferCreate: invalid TakerPays') + assertInvalid( + offer, + 'OfferCreate: invalid field TakerPays, expected a valid Amount', + ) }) it(`throws w/ invalid TakerGets`, function () { - const offerTx = { - Account: 'r3rhWeE31Jt5sWmi4QiGLMZnY3ENgqw96W', - Fee: '10', - Flags: 0, - LastLedgerSequence: 65453019, - Sequence: 40949322, - SigningPubKey: - '03C48299E57F5AE7C2BE1391B581D313F1967EA2301628C07AC412092FDC15BA22', - OfferSequence: '11', - TakerGets: 11, - TakerPays: { - currency: 'DSH', - issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX', - value: '43.11584856965009', - }, - TransactionType: 'OfferCreate', - TxnSignature: - '3045022100D874CDDD6BB24ED66E83B1D3574D3ECAC753A78F26DB7EBA89EAB8E7D72B95F802207C8CCD6CEA64E4AE2014E59EE9654E02CA8F03FE7FCE0539E958EAE182234D91', - } as any + offer.TakerGets = 11 - assertInvalid(offerTx, 'OfferCreate: invalid TakerGets') + assertInvalid( + offer, + 'OfferCreate: invalid field TakerGets, expected a valid Amount', + ) }) }) diff --git a/packages/xrpl/test/models/oracleDelete.test.ts b/packages/xrpl/test/models/oracleDelete.test.ts index 91d1561a7e..9d22db7300 100644 --- a/packages/xrpl/test/models/oracleDelete.test.ts +++ b/packages/xrpl/test/models/oracleDelete.test.ts @@ -32,8 +32,9 @@ describe('OracleDelete', function () { }) it(`throws w/ invalid OracleDocumentID`, function () { - tx.OracleDocumentID = '1234' - const errorMessage = 'OracleDelete: invalid field OracleDocumentID' + tx.OracleDocumentID = 'abcd' + const errorMessage = + 'OracleDelete: invalid field OracleDocumentID, expected a valid number' assertInvalid(tx, errorMessage) }) }) diff --git a/packages/xrpl/test/models/oracleSet.test.ts b/packages/xrpl/test/models/oracleSet.test.ts index 84c18b26e2..1e7d8f2963 100644 --- a/packages/xrpl/test/models/oracleSet.test.ts +++ b/packages/xrpl/test/models/oracleSet.test.ts @@ -48,8 +48,9 @@ describe('OracleSet', function () { }) it(`throws w/ invalid OracleDocumentID`, function () { - tx.OracleDocumentID = '1234' - const errorMessage = 'OracleSet: invalid field OracleDocumentID' + tx.OracleDocumentID = 'abcd' + const errorMessage = + 'OracleSet: invalid field OracleDocumentID, expected a valid number' assertInvalid(tx, errorMessage) }) @@ -60,26 +61,30 @@ describe('OracleSet', function () { }) it(`throws w/ invalid LastUpdateTime`, function () { - tx.LastUpdateTime = '768062172' - const errorMessage = 'OracleSet: invalid field LastUpdateTime' + tx.LastUpdateTime = 'abcd' + const errorMessage = + 'OracleSet: invalid field LastUpdateTime, expected a valid number' assertInvalid(tx, errorMessage) }) it(`throws w/ missing invalid Provider`, function () { tx.Provider = 1234 - const errorMessage = 'OracleSet: invalid field Provider' + const errorMessage = + 'OracleSet: invalid field Provider, expected a valid hex string' assertInvalid(tx, errorMessage) }) it(`throws w/ missing invalid URI`, function () { tx.URI = 1234 - const errorMessage = 'OracleSet: invalid field URI' + const errorMessage = + 'OracleSet: invalid field URI, expected a valid hex string' assertInvalid(tx, errorMessage) }) it(`throws w/ missing invalid AssetClass`, function () { tx.AssetClass = 1234 - const errorMessage = 'OracleSet: invalid field AssetClass' + const errorMessage = + 'OracleSet: invalid field AssetClass, expected a valid hex string' assertInvalid(tx, errorMessage) }) @@ -126,15 +131,14 @@ describe('OracleSet', function () { it(`throws w/ missing BaseAsset of PriceDataSeries`, function () { delete tx.PriceDataSeries[0].PriceData.BaseAsset - const errorMessage = - 'OracleSet: PriceDataSeries must have a `BaseAsset` string' + const errorMessage = 'OracleSet: missing field PriceDataSeries[0].BaseAsset' assertInvalid(tx, errorMessage) }) it(`throws w/ missing QuoteAsset of PriceDataSeries`, function () { delete tx.PriceDataSeries[0].PriceData.QuoteAsset const errorMessage = - 'OracleSet: PriceDataSeries must have a `QuoteAsset` string' + 'OracleSet: missing field PriceDataSeries[0].QuoteAsset' assertInvalid(tx, errorMessage) }) @@ -156,7 +160,7 @@ describe('OracleSet', function () { // value cannot be parsed as hexadecimal number tx.PriceDataSeries[0].PriceData.AssetPrice = 'ghij' const errorMessage = - 'OracleSet: Field AssetPrice must be a valid hex string' + 'OracleSet: invalid field PriceDataSeries[0].AssetPrice' assertInvalid(tx, errorMessage) }) @@ -169,25 +173,28 @@ describe('OracleSet', function () { it(`throws w/ invalid AssetPrice type in PriceDataSeries`, function () { tx.PriceDataSeries[0].PriceData.AssetPrice = ['sample', 'invalid', 'type'] const errorMessage = - 'OracleSet: Field AssetPrice must be a string or a number' + 'OracleSet: invalid field PriceDataSeries[0].AssetPrice' assertInvalid(tx, errorMessage) }) it(`throws w/ invalid Scale of PriceDataSeries`, function () { - tx.PriceDataSeries[0].PriceData.Scale = '1234' - const errorMessage = 'OracleSet: invalid field Scale' + tx.PriceDataSeries[0].PriceData.Scale = 'abcd' + const errorMessage = + 'OracleSet: invalid field PriceDataSeries[0].Scale, expected a valid number' assertInvalid(tx, errorMessage) }) it(`throws w/ Scale must be in range 0-10 when above max`, function () { tx.PriceDataSeries[0].PriceData.Scale = 11 - const errorMessage = 'OracleSet: Scale must be in range 0-10' + const errorMessage = + 'OracleSet: invalid field PriceDataSeries[0].Scale, expected a valid number' assertInvalid(tx, errorMessage) }) it(`throws w/ Scale must be in range 0-10 when below min`, function () { tx.PriceDataSeries[0].PriceData.Scale = -1 - const errorMessage = 'OracleSet: Scale must be in range 0-10' + const errorMessage = + 'OracleSet: invalid field PriceDataSeries[0].Scale, expected a valid number' assertInvalid(tx, errorMessage) }) }) diff --git a/packages/xrpl/test/models/payment.test.ts b/packages/xrpl/test/models/payment.test.ts index 274dc097a3..3c022f8e40 100644 --- a/packages/xrpl/test/models/payment.test.ts +++ b/packages/xrpl/test/models/payment.test.ts @@ -9,7 +9,7 @@ const assertInvalid = (tx: any, message: string): void => assertTxValidationError(tx, validatePayment, message) /** - * PaymentTransaction Verification Testing. + * Payment Verification Testing. * * Providing runtime verification testing for each specific transaction type. */ @@ -108,17 +108,20 @@ describe('Payment', function () { }, ] - assertInvalid(payment, 'BaseTransaction: invalid Memos') + assertInvalid(payment, 'BaseTransaction: invalid field Memos') }) it(`throws when Amount is missing`, function () { delete payment.Amount - assertInvalid(payment, 'PaymentTransaction: missing field Amount') + assertInvalid(payment, 'Payment: missing field Amount') }) it(`throws when Amount is invalid`, function () { payment.Amount = 1234 - assertInvalid(payment, 'PaymentTransaction: invalid Amount') + assertInvalid( + payment, + 'Payment: invalid field Amount, expected a valid Amount', + ) }) it(`throws when Destination is missing`, function () { @@ -128,12 +131,18 @@ describe('Payment', function () { it(`throws when Destination is invalid`, function () { payment.Destination = 7896214 - assertInvalid(payment, 'Payment: invalid field Destination') + assertInvalid( + payment, + 'Payment: invalid field Destination, expected a valid account address', + ) }) it(`throws when Destination is invalid classic address`, function () { payment.Destination = 'rABCD' - assertInvalid(payment, 'Payment: invalid field Destination') + assertInvalid( + payment, + 'Payment: invalid field Destination, expected a valid account address', + ) }) it(`does not throw when Destination is a valid x-address`, function () { @@ -143,27 +152,42 @@ describe('Payment', function () { it(`throws when Destination is an empty string`, function () { payment.Destination = '' - assertInvalid(payment, 'Payment: invalid field Destination') + assertInvalid( + payment, + 'Payment: invalid field Destination, expected a valid account address', + ) }) it(`throws when DestinationTag is not a number`, function () { - payment.DestinationTag = '1' - assertInvalid(payment, 'Payment: invalid field DestinationTag') + payment.DestinationTag = 'abcd' + assertInvalid( + payment, + 'Payment: invalid field DestinationTag, expected a valid number', + ) }) it(`throws when InvoiceID is not a string`, function () { payment.InvoiceID = 19832 - assertInvalid(payment, 'PaymentTransaction: InvoiceID must be a string') + assertInvalid( + payment, + 'Payment: invalid field InvoiceID, expected a valid hex string', + ) }) it(`throws when Paths is invalid`, function () { payment.Paths = [[{ account: 123 }]] - assertInvalid(payment, 'PaymentTransaction: invalid Paths') + assertInvalid( + payment, + 'Payment: invalid field Paths, expected a valid Paths array', + ) }) it(`throws when SendMax is invalid`, function () { payment.SendMax = 100000000 - assertInvalid(payment, 'PaymentTransaction: invalid SendMax') + assertInvalid( + payment, + 'Payment: invalid field SendMax, expected a valid Amount', + ) }) it(`verifies valid DeliverMin with tfPartialPayment flag set as a number`, function () { @@ -181,18 +205,21 @@ describe('Payment', function () { it(`throws when DeliverMin is invalid`, function () { payment.DeliverMin = 10000 payment.Flags = { tfPartialPayment: true } - assertInvalid(payment, 'PaymentTransaction: invalid DeliverMin') + assertInvalid( + payment, + 'Payment: invalid field DeliverMin, expected a valid Amount', + ) }) it(`throws when tfPartialPayment flag is missing with valid DeliverMin`, function () { payment.DeliverMin = '10000' assertInvalid( payment, - 'PaymentTransaction: tfPartialPayment flag required with DeliverMin', + 'Payment: tfPartialPayment flag required with DeliverMin', ) }) - it(`verifies valid MPT PaymentTransaction`, function () { + it(`verifies valid MPT Payment`, function () { const mptPayment = { TransactionType: 'Payment', Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo', @@ -209,7 +236,9 @@ describe('Payment', function () { payment.CredentialIDs = 'EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F66A' - const errorMessage = 'Payment: Credentials must be an array' + const errorMessage = + 'Payment: invalid field CredentialIDs, expected a valid array' + assertInvalid(payment, errorMessage) }) @@ -226,14 +255,15 @@ describe('Payment', function () { 'EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F662', ] - const errorMessage = 'Payment: Credentials length cannot exceed 8 elements' + const errorMessage = + 'Payment: CredentialIDs length cannot exceed 8 elements' assertInvalid(payment, errorMessage) }) it(`throws w/ empty CredentialIDs`, function () { payment.CredentialIDs = [] - const errorMessage = 'Payment: Credentials cannot be an empty array' + const errorMessage = 'Payment: CredentialIDs cannot be an empty array' assertInvalid(payment, errorMessage) }) @@ -243,7 +273,7 @@ describe('Payment', function () { 'EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F662', ] - const errorMessage = 'Payment: Invalid Credentials ID list format' + const errorMessage = 'Payment: Invalid CredentialIDs list format' assertInvalid(payment, errorMessage) }) @@ -254,7 +284,7 @@ describe('Payment', function () { ] const errorMessage = - 'Payment: Credentials cannot contain duplicate elements' + 'Payment: CredentialIDs cannot contain duplicate elements' assertInvalid(payment, errorMessage) }) }) diff --git a/packages/xrpl/test/models/paymentChannelClaim.test.ts b/packages/xrpl/test/models/paymentChannelClaim.test.ts index 2c5e0bdf4a..ab22e1a80e 100644 --- a/packages/xrpl/test/models/paymentChannelClaim.test.ts +++ b/packages/xrpl/test/models/paymentChannelClaim.test.ts @@ -45,36 +45,51 @@ describe('PaymentChannelClaim', function () { it(`throws w/ missing Channel`, function () { delete channel.Channel - assertInvalid(channel, 'PaymentChannelClaim: missing Channel') + assertInvalid(channel, 'PaymentChannelClaim: missing field Channel') }) it(`throws w/ invalid Channel`, function () { channel.Channel = 100 - assertInvalid(channel, 'PaymentChannelClaim: Channel must be a string') + assertInvalid( + channel, + 'PaymentChannelClaim: invalid field Channel, expected a valid hex string', + ) }) it(`throws w/ invalid Balance`, function () { channel.Balance = 100 - assertInvalid(channel, 'PaymentChannelClaim: Balance must be a string') + assertInvalid( + channel, + 'PaymentChannelClaim: invalid field Balance, expected a valid XRP Amount', + ) }) it(`throws w/ invalid Amount`, function () { channel.Amount = 1000 - assertInvalid(channel, 'PaymentChannelClaim: Amount must be a string') + assertInvalid( + channel, + 'PaymentChannelClaim: invalid field Amount, expected a valid XRP Amount', + ) }) it(`throws w/ invalid Signature`, function () { channel.Signature = 1000 - assertInvalid(channel, 'PaymentChannelClaim: Signature must be a string') + assertInvalid( + channel, + 'PaymentChannelClaim: invalid field Signature, expected a valid hex string', + ) }) it(`throws w/ invalid PublicKey`, function () { channel.PublicKey = ['100000'] - assertInvalid(channel, 'PaymentChannelClaim: PublicKey must be a string') + assertInvalid( + channel, + 'PaymentChannelClaim: invalid field PublicKey, expected a valid hex string', + ) }) }) diff --git a/packages/xrpl/test/models/paymentChannelCreate.test.ts b/packages/xrpl/test/models/paymentChannelCreate.test.ts index 18b560deff..8d33179d1a 100644 --- a/packages/xrpl/test/models/paymentChannelCreate.test.ts +++ b/packages/xrpl/test/models/paymentChannelCreate.test.ts @@ -44,7 +44,7 @@ describe('PaymentChannelCreate', function () { it(`missing Amount`, function () { delete channel.Amount - assertInvalid(channel, 'PaymentChannelCreate: missing Amount') + assertInvalid(channel, 'PaymentChannelCreate: missing field Amount') }) it(`missing Destination`, function () { @@ -56,48 +56,66 @@ describe('PaymentChannelCreate', function () { it(`missing SettleDelay`, function () { delete channel.SettleDelay - assertInvalid(channel, 'PaymentChannelCreate: missing SettleDelay') + assertInvalid(channel, 'PaymentChannelCreate: missing field SettleDelay') }) it(`missing PublicKey`, function () { delete channel.PublicKey - assertInvalid(channel, 'PaymentChannelCreate: missing PublicKey') + assertInvalid(channel, 'PaymentChannelCreate: missing field PublicKey') }) it(`invalid Amount`, function () { channel.Amount = 1000 - assertInvalid(channel, 'PaymentChannelCreate: Amount must be a string') + assertInvalid( + channel, + 'PaymentChannelCreate: invalid field Amount, expected a valid XRP Amount', + ) }) it(`invalid Destination`, function () { channel.Destination = 10 - assertInvalid(channel, 'PaymentChannelCreate: invalid field Destination') + assertInvalid( + channel, + 'PaymentChannelCreate: invalid field Destination, expected a valid account address', + ) }) it(`invalid SettleDelay`, function () { - channel.SettleDelay = '10' + channel.SettleDelay = 'abcd' - assertInvalid(channel, 'PaymentChannelCreate: SettleDelay must be a number') + assertInvalid( + channel, + 'PaymentChannelCreate: invalid field SettleDelay, expected a valid number', + ) }) it(`invalid PublicKey`, function () { channel.PublicKey = 10 - assertInvalid(channel, 'PaymentChannelCreate: PublicKey must be a string') + assertInvalid( + channel, + 'PaymentChannelCreate: invalid field PublicKey, expected a valid hex string', + ) }) it(`invalid DestinationTag`, function () { - channel.DestinationTag = '10' + channel.DestinationTag = 'abcd' - assertInvalid(channel, 'PaymentChannelCreate: invalid field DestinationTag') + assertInvalid( + channel, + 'PaymentChannelCreate: invalid field DestinationTag, expected a valid number', + ) }) it(`invalid CancelAfter`, function () { - channel.CancelAfter = '100' + channel.CancelAfter = 'abcd' - assertInvalid(channel, 'PaymentChannelCreate: CancelAfter must be a number') + assertInvalid( + channel, + 'PaymentChannelCreate: invalid field CancelAfter, expected a valid number', + ) }) }) diff --git a/packages/xrpl/test/models/paymentChannelFund.test.ts b/packages/xrpl/test/models/paymentChannelFund.test.ts index b7e5e4a38a..43f7068362 100644 --- a/packages/xrpl/test/models/paymentChannelFund.test.ts +++ b/packages/xrpl/test/models/paymentChannelFund.test.ts @@ -38,30 +38,39 @@ describe('PaymentChannelFund', function () { it(`throws w/ missing Amount`, function () { delete channel.Amount - assertInvalid(channel, 'PaymentChannelFund: missing Amount') + assertInvalid(channel, 'PaymentChannelFund: missing field Amount') }) it(`throws w/ missing Channel`, function () { delete channel.Channel - assertInvalid(channel, 'PaymentChannelFund: missing Channel') + assertInvalid(channel, 'PaymentChannelFund: missing field Channel') }) it(`throws w/ invalid Amount`, function () { channel.Amount = 100 - assertInvalid(channel, 'PaymentChannelFund: Amount must be a string') + assertInvalid( + channel, + 'PaymentChannelFund: invalid field Amount, expected a valid XRP Amount', + ) }) it(`throws w/ invalid Channel`, function () { channel.Channel = 1000 - assertInvalid(channel, 'PaymentChannelFund: Channel must be a string') + assertInvalid( + channel, + 'PaymentChannelFund: invalid field Channel, expected a valid hex string', + ) }) it(`throws w/ invalid Expiration`, function () { - channel.Expiration = '1000' + channel.Expiration = 'abcd' - assertInvalid(channel, 'PaymentChannelFund: Expiration must be a number') + assertInvalid( + channel, + 'PaymentChannelFund: invalid field Expiration, expected a valid number', + ) }) }) diff --git a/packages/xrpl/test/models/permissionedDomainDelete.test.ts b/packages/xrpl/test/models/permissionedDomainDelete.test.ts index 269f873dd9..692abcff3e 100644 --- a/packages/xrpl/test/models/permissionedDomainDelete.test.ts +++ b/packages/xrpl/test/models/permissionedDomainDelete.test.ts @@ -35,7 +35,8 @@ describe('PermissionedDomainDelete', function () { it(`throws w/ invalid DomainID`, function () { tx.DomainID = 1234 - const errorMessage = 'PermissionedDomainDelete: invalid field DomainID' + const errorMessage = + 'PermissionedDomainDelete: invalid field DomainID, expected a valid hex string' assertInvalid(tx, errorMessage) }) }) diff --git a/packages/xrpl/test/models/permissionedDomainSet.test.ts b/packages/xrpl/test/models/permissionedDomainSet.test.ts index 74e1cecba7..da20bc91f5 100644 --- a/packages/xrpl/test/models/permissionedDomainSet.test.ts +++ b/packages/xrpl/test/models/permissionedDomainSet.test.ts @@ -40,7 +40,8 @@ describe('PermissionedDomainSet', function () { it(`throws with invalid field DomainID`, function () { // DomainID is expected to be a string tx.DomainID = 1234 - const errorMessage = 'PermissionedDomainSet: invalid field DomainID' + const errorMessage = + 'PermissionedDomainSet: invalid field DomainID, expected a valid hex string' assertInvalid(tx, errorMessage) }) @@ -56,7 +57,7 @@ describe('PermissionedDomainSet', function () { assertInvalid( tx, - 'PermissionedDomainSet: Credentials length cannot exceed 10 elements', + 'PermissionedDomainSet: AcceptedCredentials length cannot exceed 10 elements', ) }) @@ -64,7 +65,7 @@ describe('PermissionedDomainSet', function () { tx.AcceptedCredentials = [] assertInvalid( tx, - 'PermissionedDomainSet: Credentials cannot be an empty array', + 'PermissionedDomainSet: AcceptedCredentials cannot be an empty array', ) }) @@ -72,7 +73,7 @@ describe('PermissionedDomainSet', function () { tx.AcceptedCredentials = 'AcceptedCredentials is not an array' assertInvalid( tx, - 'PermissionedDomainSet: invalid field AcceptedCredentials', + 'PermissionedDomainSet: invalid field AcceptedCredentials, expected a valid array', ) }) @@ -80,12 +81,15 @@ describe('PermissionedDomainSet', function () { tx.AcceptedCredentials = [sampleCredential, sampleCredential] assertInvalid( tx, - 'PermissionedDomainSet: Credentials cannot contain duplicate elements', + 'PermissionedDomainSet: AcceptedCredentials cannot contain duplicate elements', ) }) it('throws when AcceptedCredentials contains invalid format', function () { tx.AcceptedCredentials = [{ Field1: 'Value1', Field2: 'Value2' }] - assertInvalid(tx, 'PermissionedDomainSet: Invalid Credentials format') + assertInvalid( + tx, + 'PermissionedDomainSet: Invalid AcceptedCredentials format', + ) }) }) diff --git a/packages/xrpl/test/models/setRegularKey.test.ts b/packages/xrpl/test/models/setRegularKey.test.ts index 66a75c8d5e..1bdf753269 100644 --- a/packages/xrpl/test/models/setRegularKey.test.ts +++ b/packages/xrpl/test/models/setRegularKey.test.ts @@ -36,6 +36,9 @@ describe('SetRegularKey', function () { it(`throws w/ invalid RegularKey`, function () { tx.RegularKey = 12369846963 - assertInvalid(tx, 'SetRegularKey: RegularKey must be a string') + assertInvalid( + tx, + 'SetRegularKey: invalid field RegularKey, expected a valid account address', + ) }) }) diff --git a/packages/xrpl/test/models/signerListSet.test.ts b/packages/xrpl/test/models/signerListSet.test.ts index 6d605d5291..a641424382 100644 --- a/packages/xrpl/test/models/signerListSet.test.ts +++ b/packages/xrpl/test/models/signerListSet.test.ts @@ -66,7 +66,10 @@ describe('SignerListSet', function () { it(`throws w/ invalid SignerEntries`, function () { signerListSetTx.SignerEntries = 'khgfgyhujk' - assertInvalid(signerListSetTx, 'SignerListSet: invalid field SignerEntries') + assertInvalid( + signerListSetTx, + 'SignerListSet: invalid field SignerEntries, expected a valid array', + ) }) it(`throws w/ maximum of 32 members allowed in SignerEntries`, function () { @@ -169,7 +172,7 @@ describe('SignerListSet', function () { }, ] const errorMessage = - 'SignerListSet: WalletLocator in SignerEntry must be a 256-bit (32-byte) hexadecimal value' + 'SignerListSet: invalid field SignerEntries[0].WalletLocator, expected a valid hex string' assertInvalid(signerListSetTx, errorMessage) }) }) diff --git a/packages/xrpl/test/models/ticketCreate.test.ts b/packages/xrpl/test/models/ticketCreate.test.ts index 1cecf2dc12..6ee501c75a 100644 --- a/packages/xrpl/test/models/ticketCreate.test.ts +++ b/packages/xrpl/test/models/ticketCreate.test.ts @@ -31,15 +31,18 @@ describe('TicketCreate', function () { }) it('throws when TicketCount is not a number', function () { - ticketCreate.TicketCount = '150' - assertInvalid(ticketCreate, 'TicketCreate: TicketCount must be a number') + ticketCreate.TicketCount = 'abcd' + assertInvalid( + ticketCreate, + 'TicketCreate: invalid field TicketCount, expected a valid number', + ) }) it('throws when TicketCount is not an integer', function () { ticketCreate.TicketCount = 12.5 assertInvalid( ticketCreate, - 'TicketCreate: TicketCount must be an integer from 1 to 250', + 'TicketCreate: invalid field TicketCount, expected a valid number', ) }) @@ -47,7 +50,7 @@ describe('TicketCreate', function () { ticketCreate.TicketCount = 0 assertInvalid( ticketCreate, - 'TicketCreate: TicketCount must be an integer from 1 to 250', + 'TicketCreate: invalid field TicketCount, expected a valid number', ) }) @@ -55,7 +58,7 @@ describe('TicketCreate', function () { ticketCreate.TicketCount = 251 assertInvalid( ticketCreate, - 'TicketCreate: TicketCount must be an integer from 1 to 250', + 'TicketCreate: invalid field TicketCount, expected a valid number', ) }) }) diff --git a/packages/xrpl/test/models/trustSet.test.ts b/packages/xrpl/test/models/trustSet.test.ts index 8ea965e76c..0ab01c3ceb 100644 --- a/packages/xrpl/test/models/trustSet.test.ts +++ b/packages/xrpl/test/models/trustSet.test.ts @@ -43,16 +43,25 @@ describe('TrustSet', function () { it('throws when LimitAmount is invalid', function () { trustSet.LimitAmount = 1234 - assertInvalid(trustSet, 'TrustSet: invalid LimitAmount') + assertInvalid( + trustSet, + 'TrustSet: invalid field LimitAmount, expected a valid IOU Amount', + ) }) it('throws when QualityIn is not a number', function () { - trustSet.QualityIn = '1234' - assertInvalid(trustSet, 'TrustSet: QualityIn must be a number') + trustSet.QualityIn = 'abcd' + assertInvalid( + trustSet, + 'TrustSet: invalid field QualityIn, expected a valid number', + ) }) it('throws when QualityOut is not a number', function () { - trustSet.QualityOut = '4321' - assertInvalid(trustSet, 'TrustSet: QualityOut must be a number') + trustSet.QualityOut = 'dcba' + assertInvalid( + trustSet, + 'TrustSet: invalid field QualityOut, expected a valid number', + ) }) }) diff --git a/packages/xrpl/test/models/utils.test.ts b/packages/xrpl/test/models/utils.test.ts index 3af9a5f2e0..a1b0e62c8d 100644 --- a/packages/xrpl/test/models/utils.test.ts +++ b/packages/xrpl/test/models/utils.test.ts @@ -1,6 +1,6 @@ /* eslint-disable import/no-deprecated -- using deprecated setTransactionFlagsToNumbers to ensure no breaking changes */ /* eslint-disable no-bitwise -- flags require bitwise operations */ -import { stringToHex } from '@xrplf/isomorphic/src/utils' +import { stringToHex } from '@xrplf/isomorphic/utils' import { assert } from 'chai' import { diff --git a/packages/xrpl/test/models/vaultClawback.test.ts b/packages/xrpl/test/models/vaultClawback.test.ts index 2b63bfdfa2..b11df68a8d 100644 --- a/packages/xrpl/test/models/vaultClawback.test.ts +++ b/packages/xrpl/test/models/vaultClawback.test.ts @@ -1,4 +1,3 @@ -import { VaultClawback } from '../../src/models/transactions' import { validateVaultClawback } from '../../src/models/transactions/vaultClawback' import { assertTxIsValid, assertTxValidationError } from '../testUtils' @@ -13,7 +12,7 @@ const assertInvalid = (tx: any, message: string): void => * Provides runtime verification testing for VaultClawback transaction type. */ describe('VaultClawback', function () { - let tx: VaultClawback + let tx: any beforeEach(function () { tx = { @@ -34,32 +33,36 @@ describe('VaultClawback', function () { }) it('throws w/ missing VaultID', function () { - // @ts-expect-error for test tx.VaultID = undefined assertInvalid(tx, 'VaultClawback: missing field VaultID') }) it('throws w/ invalid VaultID', function () { - // @ts-expect-error for test tx.VaultID = 123 - assertInvalid(tx, 'VaultClawback: invalid field VaultID') + assertInvalid( + tx, + 'VaultClawback: invalid field VaultID, expected a valid hex string', + ) }) it('throws w/ missing Holder', function () { - // @ts-expect-error for test tx.Holder = undefined assertInvalid(tx, 'VaultClawback: missing field Holder') }) it('throws w/ invalid Holder', function () { - // @ts-expect-error for test tx.Holder = 123 - assertInvalid(tx, 'VaultClawback: invalid field Holder') + assertInvalid( + tx, + 'VaultClawback: invalid field Holder, expected a valid account address', + ) }) it('throws w/ string Amount', function () { - // @ts-expect-error for test tx.Amount = '123456' - assertInvalid(tx, 'VaultClawback: invalid field Amount') + assertInvalid( + tx, + 'VaultClawback: invalid field Amount, expected a valid non-XRP Amount', + ) }) }) diff --git a/packages/xrpl/test/models/vaultCreate.test.ts b/packages/xrpl/test/models/vaultCreate.test.ts index 530590416f..98df76f84e 100644 --- a/packages/xrpl/test/models/vaultCreate.test.ts +++ b/packages/xrpl/test/models/vaultCreate.test.ts @@ -2,7 +2,6 @@ import { stringToHex } from '@xrplf/isomorphic/utils' import { MPTokenMetadata } from '../../src' import { - VaultCreate, VaultCreateFlags, VaultWithdrawalPolicy, } from '../../src/models/transactions' @@ -20,7 +19,7 @@ const assertInvalid = (tx: any, message: string): void => * Providing runtime verification testing for each specific transaction type. */ describe('VaultCreate', function () { - let tx: VaultCreate + let tx: any beforeEach(function () { tx = { @@ -50,20 +49,24 @@ describe('VaultCreate', function () { }) it('throws w/ missing Asset', function () { - // @ts-expect-error for test tx.Asset = undefined assertInvalid(tx, 'VaultCreate: missing field Asset') }) it('throws w/ invalid Asset', function () { - // @ts-expect-error for test tx.Asset = 123 - assertInvalid(tx, 'VaultCreate: invalid field Asset') + assertInvalid( + tx, + 'VaultCreate: invalid field Asset, expected a valid Currency', + ) }) it('throws w/ Data field not hex', function () { tx.Data = 'zznothex' - assertInvalid(tx, 'VaultCreate: Data must be a valid hex string') + assertInvalid( + tx, + 'VaultCreate: invalid field Data, expected a valid hex string', + ) }) it('throws w/ Data field too large', function () { @@ -75,7 +78,7 @@ describe('VaultCreate', function () { tx.MPTokenMetadata = 'ggnothex' assertInvalid( tx, - 'VaultCreate: MPTokenMetadata must be a valid non-empty hex string', + 'VaultCreate: invalid field MPTokenMetadata, expected a valid hex string', ) }) @@ -88,9 +91,11 @@ describe('VaultCreate', function () { }) it('throws w/ non-number WithdrawalPolicy', function () { - // @ts-expect-error for test tx.WithdrawalPolicy = 'invalid' - assertInvalid(tx, 'VaultCreate: invalid field WithdrawalPolicy') + assertInvalid( + tx, + 'VaultCreate: invalid field WithdrawalPolicy, expected a valid number', + ) }) it('allows DomainID when tfVaultPrivate flag set', function () { @@ -186,9 +191,11 @@ describe('VaultCreate', function () { currency: 'USD', issuer: 'rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8', } - // @ts-expect-error for test tx.Scale = 'invalid' - assertInvalid(tx, 'VaultCreate: invalid field Scale') + assertInvalid( + tx, + 'VaultCreate: invalid field Scale, expected a valid number', + ) }) it('allows no Scale for IOU asset', function () { diff --git a/packages/xrpl/test/models/vaultDelete.test.ts b/packages/xrpl/test/models/vaultDelete.test.ts index da3c7f77d1..d9c251f40c 100644 --- a/packages/xrpl/test/models/vaultDelete.test.ts +++ b/packages/xrpl/test/models/vaultDelete.test.ts @@ -1,4 +1,3 @@ -import { VaultDelete } from '../../src/models/transactions' import { validateVaultDelete } from '../../src/models/transactions/vaultDelete' import { assertTxIsValid, assertTxValidationError } from '../testUtils' @@ -12,7 +11,7 @@ const assertInvalid = (tx: any, message: string): void => * Provides runtime verification testing for VaultDelete transaction type. */ describe('VaultDelete', function () { - let tx: VaultDelete + let tx: any beforeEach(function () { tx = { @@ -27,14 +26,15 @@ describe('VaultDelete', function () { }) it('throws w/ missing VaultID', function () { - // @ts-expect-error for test tx.VaultID = undefined assertInvalid(tx, 'VaultDelete: missing field VaultID') }) it('throws w/ invalid VaultID', function () { - // @ts-expect-error for test tx.VaultID = 123 - assertInvalid(tx, 'VaultDelete: invalid field VaultID') + assertInvalid( + tx, + 'VaultDelete: invalid field VaultID, expected a valid hex string', + ) }) }) diff --git a/packages/xrpl/test/models/vaultDeposit.test.ts b/packages/xrpl/test/models/vaultDeposit.test.ts index 4ebe5b97ee..ba7ee8f48f 100644 --- a/packages/xrpl/test/models/vaultDeposit.test.ts +++ b/packages/xrpl/test/models/vaultDeposit.test.ts @@ -1,4 +1,3 @@ -import { VaultDeposit } from '../../src/models/transactions' import { validateVaultDeposit } from '../../src/models/transactions/vaultDeposit' import { assertTxIsValid, assertTxValidationError } from '../testUtils' @@ -12,7 +11,7 @@ const assertInvalid = (tx: any, message: string): void => * Provides runtime verification testing for VaultDeposit transaction type. */ describe('VaultDeposit', function () { - let tx: VaultDeposit + let tx: any beforeEach(function () { tx = { @@ -28,26 +27,28 @@ describe('VaultDeposit', function () { }) it('throws w/ missing VaultID', function () { - // @ts-expect-error for test tx.VaultID = undefined assertInvalid(tx, 'VaultDeposit: missing field VaultID') }) it('throws w/ invalid VaultID', function () { - // @ts-expect-error for test tx.VaultID = 123 - assertInvalid(tx, 'VaultDeposit: invalid field VaultID') + assertInvalid( + tx, + 'VaultDeposit: invalid field VaultID, expected a valid hex string', + ) }) it('throws w/ missing Amount', function () { - // @ts-expect-error for test tx.Amount = undefined assertInvalid(tx, 'VaultDeposit: missing field Amount') }) it('throws w/ non-string Amount', function () { - // @ts-expect-error for test tx.Amount = 123 - assertInvalid(tx, 'VaultDeposit: invalid field Amount') + assertInvalid( + tx, + 'VaultDeposit: invalid field Amount, expected a valid Amount', + ) }) }) diff --git a/packages/xrpl/test/models/vaultSet.test.ts b/packages/xrpl/test/models/vaultSet.test.ts index 3261ec8d74..b450f1260f 100644 --- a/packages/xrpl/test/models/vaultSet.test.ts +++ b/packages/xrpl/test/models/vaultSet.test.ts @@ -1,6 +1,5 @@ import { stringToHex } from '@xrplf/isomorphic/utils' -import { VaultSet } from '../../src' import { validateVaultSet } from '../../src/models/transactions/vaultSet' import { assertTxIsValid, assertTxValidationError } from '../testUtils' @@ -14,7 +13,7 @@ const assertInvalid = (tx: any, message: string): void => * Providing runtime verification testing for the VaultSet transaction type. */ describe('VaultSet', function () { - let tx: VaultSet + let tx: any beforeEach(function () { tx = { @@ -29,20 +28,24 @@ describe('VaultSet', function () { }) it('throws w/ missing VaultID', function () { - // @ts-expect-error for test tx.VaultID = undefined assertInvalid(tx, 'VaultSet: missing field VaultID') }) it('throws w/ non-string VaultID', function () { - // @ts-expect-error for test tx.VaultID = 123456 - assertInvalid(tx, 'VaultSet: invalid field VaultID') + assertInvalid( + tx, + 'VaultSet: invalid field VaultID, expected a valid hex string', + ) }) it('throws w/ Data field not hex', function () { tx.Data = 'zznothex' - assertInvalid(tx, 'VaultSet: Data must be a valid hex string') + assertInvalid( + tx, + 'VaultSet: invalid field Data, expected a valid hex string', + ) }) it('throws w/ Data field too large', function () { @@ -52,18 +55,25 @@ describe('VaultSet', function () { it('throws w/ non-XRPLNumber AssetsMaximum', function () { tx.AssetsMaximum = 'notanumber' - assertInvalid(tx, 'VaultSet: invalid field AssetsMaximum') + assertInvalid( + tx, + 'VaultSet: invalid field AssetsMaximum, expected a valid XRPLNumber', + ) }) it('throws w/ non-string Data', function () { - // @ts-expect-error for test tx.Data = 1234 - assertInvalid(tx, 'VaultSet: invalid field Data') + assertInvalid( + tx, + 'VaultSet: invalid field Data, expected a valid hex string', + ) }) it('throws w/ non-string DomainID', function () { - // @ts-expect-error for test tx.DomainID = 1234 - assertInvalid(tx, 'VaultSet: invalid field DomainID') + assertInvalid( + tx, + 'VaultSet: invalid field DomainID, expected a valid hex string', + ) }) }) diff --git a/packages/xrpl/test/models/vaultWithdraw.test.ts b/packages/xrpl/test/models/vaultWithdraw.test.ts index 81341b199c..32f41b7052 100644 --- a/packages/xrpl/test/models/vaultWithdraw.test.ts +++ b/packages/xrpl/test/models/vaultWithdraw.test.ts @@ -1,7 +1,3 @@ -import { assert } from 'chai' - -import { validate } from '../../src' -import { VaultWithdraw } from '../../src/models/transactions' import { validateVaultWithdraw } from '../../src/models/transactions/vaultWithdraw' import { assertTxIsValid, assertTxValidationError } from '../testUtils' @@ -16,7 +12,7 @@ const assertInvalid = (tx: any, message: string): void => * Provides runtime verification testing for VaultWithdraw transaction type. */ describe('VaultWithdraw', function () { - let tx: VaultWithdraw + let tx: any beforeEach(function () { tx = { @@ -32,39 +28,41 @@ describe('VaultWithdraw', function () { }) it('throws w/ missing VaultID', function () { - // @ts-expect-error for test tx.VaultID = undefined assertInvalid(tx, 'VaultWithdraw: missing field VaultID') }) it('throws w/ invalid VaultID', function () { - // @ts-expect-error for test tx.VaultID = 123 - assertInvalid(tx, 'VaultWithdraw: invalid field VaultID') + assertInvalid( + tx, + 'VaultWithdraw: invalid field VaultID, expected a valid hex string', + ) }) it('throws w/ missing Amount', function () { - // @ts-expect-error for test tx.Amount = undefined assertInvalid(tx, 'VaultWithdraw: missing field Amount') }) it('throws w/ non-string Amount', function () { - // @ts-expect-error for test tx.Amount = 123 - assertInvalid(tx, 'VaultWithdraw: invalid field Amount') + assertInvalid( + tx, + 'VaultWithdraw: invalid field Amount, expected a valid Amount', + ) }) it('verifies valid VaultWithdraw with Destination', function () { tx.Destination = 'rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8' - assert.doesNotThrow(() => validateVaultWithdraw(tx)) - assert.doesNotThrow(() => validate(tx)) assertValid(tx) }) it('throws w/ invalid Destination', function () { - // @ts-expect-error for test tx.Destination = 123 - assertInvalid(tx, 'VaultWithdraw: invalid field Destination') + assertInvalid( + tx, + 'VaultWithdraw: invalid field Destination, expected a valid account address', + ) }) }) diff --git a/packages/xrpl/test/testUtils.ts b/packages/xrpl/test/testUtils.ts index 782ca590c8..ce93785261 100644 --- a/packages/xrpl/test/testUtils.ts +++ b/packages/xrpl/test/testUtils.ts @@ -78,10 +78,18 @@ export function assertTxIsValid(tx: any, validateTx: (tx: any) => void): void { export function assertTxValidationError( tx: any, validateTx: (tx: any) => void, - errorMessage: string, + errorMessage: string | RegExp, ): void { - assert.throws(() => validateTx(tx), ValidationError, errorMessage) - assert.throws(() => validate(tx), ValidationError, errorMessage) + const regex = + typeof errorMessage === 'string' + ? new RegExp( + // eslint-disable-next-line require-unicode-regexp -- TS complains if it's included + `^${errorMessage.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, + 'u', + ) + : errorMessage + assert.throws(() => validateTx(tx), ValidationError, regex) + assert.throws(() => validate(tx), ValidationError, regex) } /** diff --git a/packages/xrpl/test/wallet/index.test.ts b/packages/xrpl/test/wallet/index.test.ts index cf564173ea..73bb75990c 100644 --- a/packages/xrpl/test/wallet/index.test.ts +++ b/packages/xrpl/test/wallet/index.test.ts @@ -513,7 +513,7 @@ describe('Wallet', function () { } assert.throws(() => { Wallet.fromSeed(secret).sign(lowercaseMemoTx) - }, /BaseTransaction: invalid Memos/u) + }, /BaseTransaction: invalid field Memos/u) }) it('sign throws when MemoData is not a hex value', async function () { @@ -539,7 +539,7 @@ describe('Wallet', function () { } assert.throws(() => { Wallet.fromSeed(secret).sign(lowercaseMemoTx) - }, /BaseTransaction: invalid Memos/u) + }, /BaseTransaction: invalid field Memos/u) }) it('sign throws when MemoFormat is not a hex value', async function () { @@ -565,7 +565,7 @@ describe('Wallet', function () { } assert.throws(() => { Wallet.fromSeed(secret).sign(lowercaseMemoTx) - }, /BaseTransaction: invalid Memos/u) + }, /BaseTransaction: invalid field Memos/u) }) it('sign with EscrowFinish', async function () { @@ -722,7 +722,7 @@ describe('Wallet', function () { assert.throws(() => { wallet.sign(tx) - }, /1\.2 is an illegal amount/u) + }, /AccountSet: invalid field Fee, expected a valid XRP Amount/u) }) it('sign throws when encoded tx does not match decoded tx because of illegal higher fee', async function () { @@ -740,7 +740,7 @@ describe('Wallet', function () { assert.throws(() => { wallet.sign(tx) - }, /1123456\.7 is an illegal amount/u) + }, /AccountSet: invalid field Fee, expected a valid XRP Amount/u) }) it('sign with a ticket transaction', async function () { @@ -821,6 +821,22 @@ describe('Wallet', function () { }, /^1.1234567 is an illegal amount/u) }) + it('sign throws when an illegal amount is provided', async function () { + const payment: Transaction = { + TransactionType: 'Payment', + Account: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59', + Destination: 'rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r', + Amount: '1.0', + Flags: 2147483648, + Sequence: 23, + LastLedgerSequence: 8819954, + Fee: '12', + } + assert.throws(() => { + wallet.sign(payment) + }, /^1.0 is an illegal amount/u) + }) + const issuedCurrencyPayment: Transaction = { TransactionType: 'Payment', Account: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59', @@ -1195,7 +1211,7 @@ describe('Wallet', function () { assert.throws(() => { wallet.sign(tx) - }, /URI must be in hex format/u) + }, /^NFTokenMint: invalid field URI, expected a valid hex string$/u) }) }) diff --git a/packages/xrpl/tools/createValidateTests.js b/packages/xrpl/tools/createValidateTests.js index d51e883dcc..0a67243475 100644 --- a/packages/xrpl/tools/createValidateTests.js +++ b/packages/xrpl/tools/createValidateTests.js @@ -128,16 +128,7 @@ function processModel(model, txName) { output += ` it("throws w/ missing ${param}", function () { delete tx.${param} - assert.throws( - () => validate${txName}(tx), - ValidationError, - '${txName}: missing field ${param}', - ) - assert.throws( - () => validate(tx), - ValidationError, - '${txName}: missing field ${param}', - ) + assertInvalid(tx, '${txName}: missing field ${param}') }) ` @@ -147,16 +138,7 @@ function processModel(model, txName) { output += ` it('throws w/ invalid ${param}', function () { tx.${param} = ${fakeValue} - assert.throws( - () => validate${txName}(tx), - ValidationError, - '${txName}: invalid field ${param}', - ) - assert.throws( - () => validate(tx), - ValidationError, - '${txName}: invalid field ${param}', - ) + assertInvalid(tx, '${txName}: invalid field ${param}') }) ` @@ -165,10 +147,12 @@ function processModel(model, txName) { output = output.substring(0, output.length - 2) output += '\n})\n' output = - `import { assert } from 'chai' + `import { validate${txName} } from '../../src/models/transactions/${txName}' -import { validate, ValidationError } from '../../src' -import { validate${txName} } from '../../src/models/transactions/${txName}' +const assertValid = (tx: any): void => + assertTxIsValid(tx, validate${txName}) +const assertInvalid = (tx: any, message: string): void => + assertTxValidationError(tx, validate${txName}, message) /** * ${txName} Transaction Verification Testing. @@ -183,8 +167,7 @@ describe('${txName}', function () { }) it('verifies valid ${txName}', function () { - assert.doesNotThrow(() => validate${txName}(tx)) - assert.doesNotThrow(() => validate(tx)) + assertValid(tx) }) ` + output