xrpl
Version:
A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser
206 lines (188 loc) • 7 kB
text/typescript
import { ValidationError } from '../../errors'
import { isHex, INTEGER_SANITY_CHECK, isFlagEnabled } from '../utils'
import {
BaseTransaction,
GlobalFlagsInterface,
validateBaseTransaction,
validateOptionalField,
isString,
isNumber,
MAX_MPT_META_BYTE_LENGTH,
MPT_META_WARNING_HEADER,
validateMPTokenMetadata,
} 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.
*
* @category Transaction Flags
*/
export enum MPTokenIssuanceCreateFlags {
/**
* If set, indicates that the MPT can be locked both individually and globally.
* If not set, the MPT cannot be locked in any way.
*/
tfMPTCanLock = 0x00000002,
/**
* If set, indicates that individual holders must be authorized.
* This enables issuers to limit who can hold their assets.
*/
tfMPTRequireAuth = 0x00000004,
/**
* If set, indicates that individual holders can place their balances into an escrow.
*/
tfMPTCanEscrow = 0x00000008,
/**
* If set, indicates that individual holders can trade their balances
* using the XRP Ledger DEX or AMM.
*/
tfMPTCanTrade = 0x00000010,
/**
* If set, indicates that tokens may be transferred to other accounts
* that are not the issuer.
*/
tfMPTCanTransfer = 0x00000020,
/**
* If set, indicates that the issuer may use the Clawback transaction
* to clawback value from individual holders.
*/
tfMPTCanClawback = 0x00000040,
}
/**
* Map of flags to boolean values representing {@link MPTokenIssuanceCreate} transaction
* flags.
*
* @category Transaction Flags
*/
export interface MPTokenIssuanceCreateFlagsInterface
extends GlobalFlagsInterface {
tfMPTCanLock?: boolean
tfMPTRequireAuth?: boolean
tfMPTCanEscrow?: boolean
tfMPTCanTrade?: boolean
tfMPTCanTransfer?: boolean
tfMPTCanClawback?: boolean
}
/**
* The MPTokenIssuanceCreate transaction creates a MPTokenIssuance object
* and adds it to the relevant directory node of the creator account.
* This transaction is the only opportunity an issuer has to specify any token fields
* that are defined as immutable (e.g., MPT Flags). If the transaction is successful,
* the newly created token will be owned by the account (the creator account) which
* executed the transaction.
*/
export interface MPTokenIssuanceCreate extends BaseTransaction {
TransactionType: 'MPTokenIssuanceCreate'
/**
* An asset scale is the difference, in orders of magnitude, between a standard unit and
* a corresponding fractional unit. More formally, the asset scale is a non-negative integer
* (0, 1, 2, …) such that one standard unit equals 10^(-scale) of a corresponding
* fractional unit. If the fractional unit equals the standard unit, then the asset scale is 0.
* Note that this value is optional, and will default to 0 if not supplied.
*/
AssetScale?: number
/**
* Specifies the maximum asset amount of this token that should ever be issued.
* It is a non-negative integer string that can store a range of up to 63 bits. If not set, the max
* amount will default to the largest unsigned 63-bit integer (0x7FFFFFFFFFFFFFFF or 9223372036854775807)
*
* Example:
* ```
* MaximumAmount: '9223372036854775807'
* ```
*/
MaximumAmount?: string
/**
* Specifies the fee to charged by the issuer for secondary sales of the Token,
* if such sales are allowed. Valid values for this field are between 0 and 50,000 inclusive,
* allowing transfer rates of between 0.000% and 50.000% in increments of 0.001.
* The field must NOT be present if the `tfMPTCanTransfer` flag is not set.
*/
TransferFee?: number
/**
* Optional arbitrary metadata about this issuance, encoded as a hex string and limited to 1024 bytes.
*
* The decoded value must be a UTF-8 encoded JSON object that adheres to the
* XLS-89d MPTokenMetadata standard.
*
* While adherence to the XLS-89d format is not mandatory, non-compliant metadata
* may not be discoverable by ecosystem tools such as explorers and indexers.
*/
MPTokenMetadata?: string
Flags?: number | MPTokenIssuanceCreateFlagsInterface
}
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.
*
* @param tx - An MPTokenIssuanceCreate Transaction.
* @throws When the MPTokenIssuanceCreate is Malformed.
*/
export function validateMPTokenIssuanceCreate(
tx: Record<string, unknown>,
): void {
validateBaseTransaction(tx)
validateOptionalField(tx, 'MaximumAmount', isString)
validateOptionalField(tx, 'MPTokenMetadata', isString)
validateOptionalField(tx, 'TransferFee', isNumber)
validateOptionalField(tx, 'AssetScale', isNumber)
if (
typeof tx.MPTokenMetadata === 'string' &&
(!isHex(tx.MPTokenMetadata) ||
tx.MPTokenMetadata.length / 2 > MAX_MPT_META_BYTE_LENGTH)
) {
throw new ValidationError(
`MPTokenIssuanceCreate: MPTokenMetadata (hex format) must be non-empty and no more than ${MAX_MPT_META_BYTE_LENGTH} bytes.`,
)
}
if (typeof tx.MaximumAmount === 'string') {
if (!INTEGER_SANITY_CHECK.exec(tx.MaximumAmount)) {
throw new ValidationError('MPTokenIssuanceCreate: Invalid MaximumAmount')
} else if (
BigInt(tx.MaximumAmount) > BigInt(MAX_AMT) ||
BigInt(tx.MaximumAmount) < BigInt(`0`)
) {
throw new ValidationError(
'MPTokenIssuanceCreate: MaximumAmount out of range',
)
}
}
if (typeof tx.TransferFee === 'number') {
// 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
if (tx.TransferFee < 0 || tx.TransferFee > MAX_TRANSFER_FEE) {
throw new ValidationError(
`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',
)
}
}
if (tx.MPTokenMetadata != null) {
const validationMessages = validateMPTokenMetadata(tx.MPTokenMetadata)
if (validationMessages.length > 0) {
const message = [
MPT_META_WARNING_HEADER,
...validationMessages.map((msg) => `- ${msg}`),
].join('\n')
// eslint-disable-next-line no-console -- Required here.
console.warn(message)
}
}
}
/* eslint-enable max-lines-per-function */