mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-07 06:15:49 +00:00
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:
@@ -1,5 +1,5 @@
|
|||||||
import { ValidationError } from '../../errors'
|
import { ValidationError } from '../../errors'
|
||||||
import { isHex, INTEGER_SANITY_CHECK } from '../utils'
|
import { isHex, INTEGER_SANITY_CHECK, isFlagEnabled } from '../utils'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BaseTransaction,
|
BaseTransaction,
|
||||||
@@ -7,11 +7,13 @@ import {
|
|||||||
validateBaseTransaction,
|
validateBaseTransaction,
|
||||||
validateOptionalField,
|
validateOptionalField,
|
||||||
isString,
|
isString,
|
||||||
|
isNumber,
|
||||||
} from './common'
|
} from './common'
|
||||||
import type { TransactionMetadataBase } from './metadata'
|
import type { TransactionMetadataBase } from './metadata'
|
||||||
|
|
||||||
// 2^63 - 1
|
// 2^63 - 1
|
||||||
const MAX_AMT = '9223372036854775807'
|
const MAX_AMT = '9223372036854775807'
|
||||||
|
const MAX_TRANSFER_FEE = 50000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transaction Flags for an MPTokenIssuanceCreate Transaction.
|
* Transaction Flags for an MPTokenIssuanceCreate Transaction.
|
||||||
@@ -112,6 +114,7 @@ export interface MPTokenIssuanceCreateMetadata extends TransactionMetadataBase {
|
|||||||
mpt_issuance_id?: string
|
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.
|
* Verify the form and type of an MPTokenIssuanceCreate at runtime.
|
||||||
*
|
*
|
||||||
@@ -124,6 +127,8 @@ export function validateMPTokenIssuanceCreate(
|
|||||||
validateBaseTransaction(tx)
|
validateBaseTransaction(tx)
|
||||||
validateOptionalField(tx, 'MaximumAmount', isString)
|
validateOptionalField(tx, 'MaximumAmount', isString)
|
||||||
validateOptionalField(tx, 'MPTokenMetadata', isString)
|
validateOptionalField(tx, 'MPTokenMetadata', isString)
|
||||||
|
validateOptionalField(tx, 'TransferFee', isNumber)
|
||||||
|
validateOptionalField(tx, 'AssetScale', isNumber)
|
||||||
|
|
||||||
if (typeof tx.MPTokenMetadata === 'string' && tx.MPTokenMetadata === '') {
|
if (typeof tx.MPTokenMetadata === 'string' && tx.MPTokenMetadata === '') {
|
||||||
throw new ValidationError(
|
throw new ValidationError(
|
||||||
@@ -150,12 +155,25 @@ export function validateMPTokenIssuanceCreate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_TRANSFER_FEE = 50000
|
|
||||||
if (typeof tx.TransferFee === 'number') {
|
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) {
|
if (tx.TransferFee < 0 || tx.TransferFee > MAX_TRANSFER_FEE) {
|
||||||
throw new ValidationError(
|
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 */
|
||||||
|
|||||||
@@ -68,15 +68,19 @@ export function validateMPTokenIssuanceSet(tx: Record<string, unknown>): void {
|
|||||||
validateRequiredField(tx, 'MPTokenIssuanceID', isString)
|
validateRequiredField(tx, 'MPTokenIssuanceID', isString)
|
||||||
validateOptionalField(tx, 'Holder', isAccount)
|
validateOptionalField(tx, 'Holder', isAccount)
|
||||||
|
|
||||||
if (typeof tx.Flags === 'number') {
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Not necessary
|
||||||
const flags = tx.Flags
|
const flags = tx.Flags as number | MPTokenIssuanceSetFlagsInterface
|
||||||
if (
|
const isTfMPTLock =
|
||||||
isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTLock) &&
|
typeof flags === 'number'
|
||||||
isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTUnlock)
|
? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTLock)
|
||||||
) {
|
: flags.tfMPTLock ?? false
|
||||||
throw new ValidationError('MPTokenIssuanceSet: flag conflict')
|
|
||||||
}
|
const isTfMPTUnlock =
|
||||||
} else {
|
typeof flags === 'number'
|
||||||
throw new Error('tx.Flags is not a number')
|
? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTUnlock)
|
||||||
|
: flags.tfMPTUnlock ?? false
|
||||||
|
|
||||||
|
if (isTfMPTLock && isTfMPTUnlock) {
|
||||||
|
throw new ValidationError('MPTokenIssuanceSet: flag conflict')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ describe('MPTokenIssuanceCreate', function () {
|
|||||||
MaximumAmount: '9223372036854775807',
|
MaximumAmount: '9223372036854775807',
|
||||||
AssetScale: 2,
|
AssetScale: 2,
|
||||||
TransferFee: 1,
|
TransferFee: 1,
|
||||||
Flags: 2,
|
Flags: MPTokenIssuanceCreateFlags.tfMPTCanTransfer,
|
||||||
MPTokenMetadata: convertStringToHex('http://xrpl.org'),
|
MPTokenMetadata: convertStringToHex('http://xrpl.org'),
|
||||||
} as any
|
} as any
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ describe('MPTokenIssuanceCreate', function () {
|
|||||||
assert.throws(
|
assert.throws(
|
||||||
() => validate(invalid),
|
() => validate(invalid),
|
||||||
ValidationError,
|
ValidationError,
|
||||||
'MPTokenIssuanceCreate: TransferFee out of range',
|
'MPTokenIssuanceCreate: TransferFee must be between 0 and 50000',
|
||||||
)
|
)
|
||||||
|
|
||||||
invalid = {
|
invalid = {
|
||||||
@@ -118,7 +118,32 @@ describe('MPTokenIssuanceCreate', function () {
|
|||||||
assert.throws(
|
assert.throws(
|
||||||
() => validate(invalid),
|
() => validate(invalid),
|
||||||
ValidationError,
|
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',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ describe('MPTokenIssuanceSet', function () {
|
|||||||
} as any
|
} as any
|
||||||
|
|
||||||
assert.doesNotThrow(() => validate(validMPTokenIssuanceSet))
|
assert.doesNotThrow(() => validate(validMPTokenIssuanceSet))
|
||||||
|
|
||||||
validMPTokenIssuanceSet = {
|
validMPTokenIssuanceSet = {
|
||||||
TransactionType: 'MPTokenIssuanceSet',
|
TransactionType: 'MPTokenIssuanceSet',
|
||||||
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
@@ -54,15 +55,23 @@ describe('MPTokenIssuanceSet', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it(`throws w/ conflicting flags`, function () {
|
it(`throws w/ conflicting flags`, function () {
|
||||||
/* eslint-disable no-bitwise -- Bitwise operation needed for flag combination */
|
|
||||||
const invalid = {
|
const invalid = {
|
||||||
TransactionType: 'MPTokenIssuanceSet',
|
TransactionType: 'MPTokenIssuanceSet',
|
||||||
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
MPTokenIssuanceID: TOKEN_ID,
|
MPTokenIssuanceID: TOKEN_ID,
|
||||||
Flags:
|
|
||||||
MPTokenIssuanceSetFlags.tfMPTLock | MPTokenIssuanceSetFlags.tfMPTUnlock,
|
|
||||||
} as any
|
} 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(
|
assert.throws(
|
||||||
() => validate(invalid),
|
() => validate(invalid),
|
||||||
|
|||||||
Reference in New Issue
Block a user