add more mpt flag validations (#2856)

* remove else condition

* validation txfee

* clidation

* lint

* lint

* comments

* lint

* more typechecking

* rm newline

* refactor

* null check

* revert null check

* reuse test
This commit is contained in:
Shawn Xie
2024-12-19 15:53:16 -05:00
committed by GitHub
parent 303c2b983c
commit 7bf6fecc71
4 changed files with 76 additions and 20 deletions

View File

@@ -1,5 +1,5 @@
import { ValidationError } from '../../errors'
import { isHex, INTEGER_SANITY_CHECK } from '../utils'
import { isHex, INTEGER_SANITY_CHECK, isFlagEnabled } from '../utils'
import {
BaseTransaction,
@@ -7,11 +7,13 @@ import {
validateBaseTransaction,
validateOptionalField,
isString,
isNumber,
} from './common'
import type { TransactionMetadataBase } from './metadata'
// 2^63 - 1
const MAX_AMT = '9223372036854775807'
const MAX_TRANSFER_FEE = 50000
/**
* Transaction Flags for an MPTokenIssuanceCreate Transaction.
@@ -112,6 +114,7 @@ export interface MPTokenIssuanceCreateMetadata extends TransactionMetadataBase {
mpt_issuance_id?: string
}
/* eslint-disable max-lines-per-function -- Not needed to reduce function */
/**
* Verify the form and type of an MPTokenIssuanceCreate at runtime.
*
@@ -124,6 +127,8 @@ export function validateMPTokenIssuanceCreate(
validateBaseTransaction(tx)
validateOptionalField(tx, 'MaximumAmount', isString)
validateOptionalField(tx, 'MPTokenMetadata', isString)
validateOptionalField(tx, 'TransferFee', isNumber)
validateOptionalField(tx, 'AssetScale', isNumber)
if (typeof tx.MPTokenMetadata === 'string' && tx.MPTokenMetadata === '') {
throw new ValidationError(
@@ -150,12 +155,25 @@ export function validateMPTokenIssuanceCreate(
}
}
const MAX_TRANSFER_FEE = 50000
if (typeof tx.TransferFee === 'number') {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Not necessary
const flags = tx.Flags as number | MPTokenIssuanceCreateFlagsInterface
const isTfMPTCanTransfer =
typeof flags === 'number'
? isFlagEnabled(flags, MPTokenIssuanceCreateFlags.tfMPTCanTransfer)
: flags.tfMPTCanTransfer ?? false
if (tx.TransferFee < 0 || tx.TransferFee > MAX_TRANSFER_FEE) {
throw new ValidationError(
'MPTokenIssuanceCreate: TransferFee out of range',
`MPTokenIssuanceCreate: TransferFee must be between 0 and ${MAX_TRANSFER_FEE}`,
)
}
if (tx.TransferFee && !isTfMPTCanTransfer) {
throw new ValidationError(
'MPTokenIssuanceCreate: TransferFee cannot be provided without enabling tfMPTCanTransfer flag',
)
}
}
}
/* eslint-enable max-lines-per-function */

View File

@@ -68,15 +68,19 @@ export function validateMPTokenIssuanceSet(tx: Record<string, unknown>): void {
validateRequiredField(tx, 'MPTokenIssuanceID', isString)
validateOptionalField(tx, 'Holder', isAccount)
if (typeof tx.Flags === 'number') {
const flags = tx.Flags
if (
isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTLock) &&
isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTUnlock)
) {
throw new ValidationError('MPTokenIssuanceSet: flag conflict')
}
} else {
throw new Error('tx.Flags is not a number')
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Not necessary
const flags = tx.Flags as number | MPTokenIssuanceSetFlagsInterface
const isTfMPTLock =
typeof flags === 'number'
? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTLock)
: flags.tfMPTLock ?? false
const isTfMPTUnlock =
typeof flags === 'number'
? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTUnlock)
: flags.tfMPTUnlock ?? false
if (isTfMPTLock && isTfMPTUnlock) {
throw new ValidationError('MPTokenIssuanceSet: flag conflict')
}
}

View File

@@ -21,7 +21,7 @@ describe('MPTokenIssuanceCreate', function () {
MaximumAmount: '9223372036854775807',
AssetScale: 2,
TransferFee: 1,
Flags: 2,
Flags: MPTokenIssuanceCreateFlags.tfMPTCanTransfer,
MPTokenMetadata: convertStringToHex('http://xrpl.org'),
} as any
@@ -106,7 +106,7 @@ describe('MPTokenIssuanceCreate', function () {
assert.throws(
() => validate(invalid),
ValidationError,
'MPTokenIssuanceCreate: TransferFee out of range',
'MPTokenIssuanceCreate: TransferFee must be between 0 and 50000',
)
invalid = {
@@ -118,7 +118,32 @@ describe('MPTokenIssuanceCreate', function () {
assert.throws(
() => validate(invalid),
ValidationError,
'MPTokenIssuanceCreate: TransferFee out of range',
'MPTokenIssuanceCreate: TransferFee must be between 0 and 50000',
)
invalid = {
TransactionType: 'MPTokenIssuanceCreate',
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
TransferFee: 100,
} as any
assert.throws(
() => validate(invalid),
ValidationError,
'MPTokenIssuanceCreate: TransferFee cannot be provided without enabling tfMPTCanTransfer flag',
)
invalid = {
TransactionType: 'MPTokenIssuanceCreate',
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
TransferFee: 100,
Flags: { tfMPTCanClawback: true },
} as any
assert.throws(
() => validate(invalid),
ValidationError,
'MPTokenIssuanceCreate: TransferFee cannot be provided without enabling tfMPTCanTransfer flag',
)
})
})

View File

@@ -19,6 +19,7 @@ describe('MPTokenIssuanceSet', function () {
} as any
assert.doesNotThrow(() => validate(validMPTokenIssuanceSet))
validMPTokenIssuanceSet = {
TransactionType: 'MPTokenIssuanceSet',
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
@@ -54,15 +55,23 @@ describe('MPTokenIssuanceSet', function () {
})
it(`throws w/ conflicting flags`, function () {
/* eslint-disable no-bitwise -- Bitwise operation needed for flag combination */
const invalid = {
TransactionType: 'MPTokenIssuanceSet',
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
MPTokenIssuanceID: TOKEN_ID,
Flags:
MPTokenIssuanceSetFlags.tfMPTLock | MPTokenIssuanceSetFlags.tfMPTUnlock,
} as any
/* eslint-enable no-bitwise -- Re-enable bitwise rule */
invalid.Flags =
// eslint-disable-next-line no-bitwise -- not needed
MPTokenIssuanceSetFlags.tfMPTLock | MPTokenIssuanceSetFlags.tfMPTUnlock
assert.throws(
() => validate(invalid),
ValidationError,
'MPTokenIssuanceSet: flag conflict',
)
invalid.Flags = { tfMPTLock: true, tfMPTUnlock: true }
assert.throws(
() => validate(invalid),