-
Notifications
You must be signed in to change notification settings - Fork 560
Support for Dynamic MPTs (XLS-94D) #3081
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughAdds DynamicMPT to CI config; registers a serialized Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Potential focus areas:
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (5)
packages/xrpl/HISTORY.md (1)
7-9: Standardize XLS casing and add spec linkUse the conventional lowercase “d” and link the spec for consistency with prior entries.
-* Support for `Dynamic MPT` (XLS-94D) +* Support for `Dynamic MPT` ([XLS-94d](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0094-dynamic-MPT))packages/xrpl/src/models/ledger/MPTokenIssuance.ts (2)
18-59: Separate flag maps for Flags vs MutableFlags to avoid misuseCombining base flags and “can‑mutate” booleans in one interface invites accidental mixing. Define a distinct interface for MutableFlags and use clearer naming in call sites.
-export interface MPTokenIssuanceFlagsInterface { +export interface MPTokenIssuanceFlagsInterface { lsfMPTLocked?: boolean lsfMPTCanLock?: boolean lsfMPTRequireAuth?: boolean lsfMPTCanEscrow?: boolean lsfMPTCanTrade?: boolean lsfMPTCanTransfer?: boolean lsfMPTCanClawback?: boolean - /** - * Indicates flag lsfMPTCanLock can be changed - */ - lsfMPTCanMutateCanLock?: boolean +} + +export interface MPTokenIssuanceMutableFlagsInterface { + /** Indicates flag lsfMPTCanLock can be changed */ + lsfMPTCanMutateCanLock?: boolean /** Indicates flag lsfMPTRequireAuth can be changed */ lsfMPTCanMutateRequireAuth?: boolean /** Indicates flag lsfMPTCanEscrow can be changed */ lsfMPTCanMutateCanEscrow?: boolean /** Indicates flag lsfMPTCanTrade can be changed */ lsfMPTCanMutateCanTrade?: boolean /** Indicates flag lsfMPTCanTransfer can be changed */ lsfMPTCanMutateCanTransfer?: boolean /** Indicates flag lsfMPTCanClawback can be changed */ lsfMPTCanMutateCanClawback?: boolean /** Allows field MPTokenMetadata to be modified */ lsfMPTCanMutateMetadata?: boolean /** Allows field TransferFee to be modified */ lsfMPTCanMutateTransferFee?: boolean }
61-102: Split enums for clarity: Flags vs MutableFlags share bit positionsReusing the same bit values for two different bitmaps is correct but confusing in a single enum. Create a second enum (MPTokenIssuanceMutableFlags) for the MutableFlags field and leave MPTokenIssuanceFlags for Flags only.
-export enum MPTokenIssuanceFlags { +export enum MPTokenIssuanceFlags { lsfMPTLocked = 0x00000001, lsfMPTCanLock = 0x00000002, lsfMPTRequireAuth = 0x00000004, lsfMPTCanEscrow = 0x00000008, lsfMPTCanTrade = 0x00000010, lsfMPTCanTransfer = 0x00000020, lsfMPTCanClawback = 0x00000040, - - /** - * Indicates flag lsfMPTCanLock can be changed - */ - lsfMPTCanMutateCanLock = 0x00000002, - /** Indicates flag lsfMPTRequireAuth can be changed */ - lsfMPTCanMutateRequireAuth = 0x00000004, - /** Indicates flag lsfMPTCanEscrow can be changed */ - lsfMPTCanMutateCanEscrow = 0x00000008, - /** Indicates flag lsfMPTCanTrade can be changed */ - lsfMPTCanMutateCanTrade = 0x00000010, - /** Indicates flag lsfMPTCanTransfer can be changed */ - lsfMPTCanMutateCanTransfer = 0x00000020, - /** Indicates flag lsfMPTCanClawback can be changed */ - lsfMPTCanMutateCanClawback = 0x00000040, - /** Allows field MPTokenMetadata to be modified */ - lsfMPTCanMutateMetadata = 0x00010000, - /** Allows field TransferFee to be modified */ - lsfMPTCanMutateTransferFee = 0x00020000, } + +export enum MPTokenIssuanceMutableFlags { + /** Indicates flag lsfMPTCanLock can be changed */ + lsfMPTCanMutateCanLock = 0x00000002, + /** Indicates flag lsfMPTRequireAuth can be changed */ + lsfMPTCanMutateRequireAuth = 0x00000004, + /** Indicates flag lsfMPTCanEscrow can be changed */ + lsfMPTCanMutateCanEscrow = 0x00000008, + /** Indicates flag lsfMPTCanTrade can be changed */ + lsfMPTCanMutateCanTrade = 0x00000010, + /** Indicates flag lsfMPTCanTransfer can be changed */ + lsfMPTCanMutateCanTransfer = 0x00000020, + /** Indicates flag lsfMPTCanClawback can be changed */ + lsfMPTCanMutateCanClawback = 0x00000040, + /** Allows field MPTokenMetadata to be modified */ + lsfMPTCanMutateMetadata = 0x00010000, + /** Allows field TransferFee to be modified */ + lsfMPTCanMutateTransferFee = 0x00020000, +}packages/xrpl/test/integration/transactions/mptokenIssuanceSet.test.ts (1)
87-88: Arithmetic addition of flags could lead to incorrect valuesUsing arithmetic addition (
+) to combine flags is error-prone and could result in incorrect values if the same flag is accidentally included twice. Bitwise OR should be used for combining flags.Use bitwise OR to combine flags:
- MutableFlags: - MPTokenIssuanceCreateFlags.tfMPTCanMutateTransferFee + - MPTokenIssuanceCreateFlags.tfMPTCanMutateCanTransfer, + MutableFlags: + MPTokenIssuanceCreateFlags.tfMPTCanMutateTransferFee | + MPTokenIssuanceCreateFlags.tfMPTCanMutateCanTransfer,packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (1)
30-77: Documentation style inconsistencyThe new flags use C-style comments (
/* */) while the existing code uses JSDoc style (/** */). This creates inconsistency in the documentation format.Convert to JSDoc style for consistency:
- // The below flags are used in the MutableFlags field - /* - ** Sets the lsfMPTCanLock flag. Enables the token to be locked both individually and globally. - */ + // The below flags are used in the MutableFlags field + /** + * Sets the lsfMPTCanLock flag. Enables the token to be locked both individually and globally. + */ tfMPTSetCanLock = 0x00000001,Apply this pattern to all the new flag documentation comments.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
.ci-config/rippled.cfg(1 hunks)packages/ripple-binary-codec/src/enums/definitions.json(1 hunks)packages/xrpl/HISTORY.md(1 hunks)packages/xrpl/src/models/ledger/LedgerEntry.ts(2 hunks)packages/xrpl/src/models/ledger/MPTokenIssuance.ts(1 hunks)packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts(3 hunks)packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts(3 hunks)packages/xrpl/test/integration/transactions/mptokenIssuanceSet.test.ts(1 hunks)packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts(1 hunks)packages/xrpl/test/models/MPTokenIssuanceSet.test.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-12-06T18:44:55.095Z
Learnt from: shawnxie999
PR: XRPLF/xrpl.js#2661
File: packages/xrpl/test/models/MPTokenAuthorize.test.ts:60-71
Timestamp: 2024-12-06T18:44:55.095Z
Learning: In the XRPL.js library's TypeScript test file `packages/xrpl/test/models/MPTokenAuthorize.test.ts`, negative test cases for invalid `Account` address format, invalid `Holder` address format, invalid `MPTokenIssuanceID` format, and invalid flag combinations are not necessary.
Applied to files:
packages/xrpl/test/models/MPTokenIssuanceSet.test.tspackages/xrpl/src/models/ledger/MPTokenIssuance.tspackages/xrpl/test/models/MPTokenIssuanceCreate.test.tspackages/xrpl/test/integration/transactions/mptokenIssuanceSet.test.tspackages/xrpl/src/models/transactions/MPTokenIssuanceCreate.tspackages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts
🧬 Code graph analysis (4)
packages/xrpl/src/models/ledger/LedgerEntry.ts (2)
packages/xrpl/src/models/ledger/MPTokenIssuance.ts (1)
MPTokenIssuance(3-16)packages/xrpl/src/models/ledger/index.ts (1)
MPTokenIssuance(65-65)
packages/xrpl/test/models/MPTokenIssuanceSet.test.ts (1)
packages/xrpl/src/models/transactions/index.ts (1)
MPTokenIssuanceSetFlags(65-65)
packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts (1)
packages/xrpl/src/models/transactions/index.ts (1)
MPTokenIssuanceCreateFlags(59-59)
packages/xrpl/test/integration/transactions/mptokenIssuanceSet.test.ts (4)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
MPTokenIssuanceCreate(100-142)packages/xrpl/test/integration/utils.ts (1)
testTransaction(240-290)packages/xrpl/src/models/transactions/metadata.ts (1)
TransactionMetadata(95-108)packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (1)
MPTokenIssuanceSet(144-160)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: integration (20.x)
- GitHub Check: integration (22.x)
- GitHub Check: unit (20.x)
- GitHub Check: browser (22.x)
- GitHub Check: unit (22.x)
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (9)
packages/xrpl/src/models/ledger/MPTokenIssuance.ts (1)
14-16: Is MutableFlags always present on-ledger?Interface marks MutableFlags as required. Confirm rippled always emits this field; if not, make it optional to avoid unnecessary ts friction when decoding historical or pre‑amendment data.
- MutableFlags: number + MutableFlags?: numberpackages/xrpl/src/models/ledger/LedgerEntry.ts (3)
13-13: Import looks goodImporting MPTokenIssuance here is appropriate.
50-51: Union extension LGTMIncluding MPTokenIssuance in the LedgerEntry union aligns with the new ledger object.
66-68: No change required — 'mpt_issuance' and 'mptoken' are the canonical rippled filter keys.Confirmed: rippled/XLS docs and the public API mapping list
MPTokenIssuance -> mpt_issuanceandMPToken -> mptoken, and the repo's ledger/ledgerEntry interfaces/tests already use those keys. (github.com).ci-config/rippled.cfg (1)
191-197: Confirm rippled image/tag and that the [features] stanza is honored (one DynamicMPT entry found)Found a single "DynamicMPT" at .ci-config/rippled.cfg:196. The CI rippled image/tag wasn't located by the prior search — verify the rippled image/tag used by CI and that the container applies the config's [features] stanza (not started in a mode that ignores it).
- Locate rippled image references in the repo: rg -n --hidden -S 'image:.rippled' --glob '**/.yml' --glob '/*.yaml' --glob '/Dockerfile' || true
- Inspect the features block and nearby lines: sed -n '184,204p' .ci-config/rippled.cfg && rg -n '^[features]' .ci-config/rippled.cfg || true
- Check CI startup/entrypoint for flags that override/ignore config: rg -n --hidden -S 'rippled.(--conf|--cfg|--standalone|--run)' --glob '**/.yml' --glob '**/Dockerfile' || true
If the rippled build used by CI lacks DynamicMPT, bump the rippled image/tag to a build that includes DynamicMPT or add the amendment ID explicitly to the config.
packages/ripple-binary-codec/src/enums/definitions.json (1)
683-692: MutableFlags (UInt32, nth=53) — unique in definitions.jsonVerified: 51 UInt32 entries; no duplicate nth values; MutableFlags is at FIELDS/68 with nth=53.
Action: verify that rippled's codec maps MutableFlags to field code 53 to avoid signing/encode mismatches.packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts (1)
31-31: Test uses potentially incorrect flag valueBased on the flag collision issue identified in the source file, this test might be using an incorrect flag value. If the mutable flags are updated to use distinct values, this test will need to be updated accordingly.
Once the flag values are corrected in the source file, update this test to use the new value for
tfMPTCanMutateTransferFee.packages/xrpl/test/models/MPTokenIssuanceSet.test.ts (1)
48-53: Good test coverage for MutableFlagsThe test properly validates that transactions with
MutableFlagsare accepted by the validator, which aligns with the Dynamic MPT specification.packages/xrpl/test/integration/transactions/mptokenIssuanceSet.test.ts (1)
79-138: Comprehensive integration test for Dynamic MPTThis test effectively validates the Dynamic MPT (XLS-94D) functionality by:
- Creating an MPT with mutable flags
- Setting a transfer fee dynamically
- Clearing the transfer capability
The test flow properly exercises the new mutability features.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
188-209: Bug: TransferFee presence check ignores 0-value caseDocs say “must NOT be present if tfMPTCanTransfer is not set.” Current check uses truthiness, so TransferFee=0 slips through.
Apply this diff:
- if (tx.TransferFee && !isTfMPTCanTransfer) { + if (tx.TransferFee !== undefined && !isTfMPTCanTransfer) { throw new ValidationError( 'MPTokenIssuanceCreate: TransferFee cannot be provided without enabling tfMPTCanTransfer flag', ) }Additionally, consider requiring an integer value:
- validateOptionalField(tx, 'TransferFee', isNumber) + validateOptionalField(tx, 'TransferFee', isNumber) + if (typeof tx.TransferFee === 'number' && !Number.isInteger(tx.TransferFee)) { + throw new ValidationError('MPTokenIssuanceCreate: TransferFee must be an integer') + }
♻️ Duplicate comments (2)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
57-64: Flag value “collisions” are OK here (separate bitfields)These tfMPTCanMutate* values matching the base flags is intentional since Flags vs MutableFlags are distinct fields. No change needed.
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (1)
205-213: Add conflict checks for Set/Clear pairs in MutableFlagsPrevent simultaneously setting and clearing the same property in one tx.
Apply this diff:
if ( typeof tx.MPTokenMetadata === 'string' && (!isHex(tx.MPTokenMetadata) || tx.MPTokenMetadata.length / 2 > MAX_MPT_META_BYTE_LENGTH) ) { throw new ValidationError( `MPTokenIssuanceSet: MPTokenMetadata (hex format) must be non-empty and no more than ${MAX_MPT_META_BYTE_LENGTH} bytes.`, ) } + + if (typeof tx.MutableFlags === 'number') { + const mf = tx.MutableFlags + const pairs: Array<[number, number, string]> = [ + [MPTokenIssuanceSetFlags.tfMPTSetCanLock, MPTokenIssuanceSetFlags.tfMPTClearCanLock, 'CanLock'], + [MPTokenIssuanceSetFlags.tfMPTSetRequireAuth, MPTokenIssuanceSetFlags.tfMPTClearRequireAuth, 'RequireAuth'], + [MPTokenIssuanceSetFlags.tfMPTSetCanEscrow, MPTokenIssuanceSetFlags.tfMPTClearCanEscrow, 'CanEscrow'], + [MPTokenIssuanceSetFlags.tfMPTSetCanTrade, MPTokenIssuanceSetFlags.tfMPTClearCanTrade, 'CanTrade'], + [MPTokenIssuanceSetFlags.tfMPTSetCanTransfer, MPTokenIssuanceSetFlags.tfMPTClearCanTransfer, 'CanTransfer'], + [MPTokenIssuanceSetFlags.tfMPTSetCanClawback, MPTokenIssuanceSetFlags.tfMPTClearCanClawback, 'CanClawback'], + ] + for (const [setBit, clearBit, name] of pairs) { + if ((mf & setBit) !== 0 && (mf & clearBit) !== 0) { + throw new ValidationError( + `MPTokenIssuanceSet: MutableFlags conflict for ${name} (set and clear both specified)`, + ) + } + } + }
🧹 Nitpick comments (3)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
163-164: Tighten validation: require integer for bitmasksMutableFlags is a bitmask; accept only finite integers (e.g., Number.isInteger) and, ideally, constrain to UInt32.
Apply this diff to align with other integer checks:
-import { +import { BaseTransaction, GlobalFlagsInterface, validateBaseTransaction, validateOptionalField, isString, - isNumber, + isNumber, + isInteger, MAX_MPT_META_BYTE_LENGTH, MPT_META_WARNING_HEADER, validateMPTokenMetadata, } from './common' @@ - validateOptionalField(tx, 'MutableFlags', isNumber) + validateOptionalField(tx, 'MutableFlags', isInteger) + if (typeof tx.MutableFlags === 'number') { + if (tx.MutableFlags < 0 || tx.MutableFlags > 0xffffffff) { + throw new ValidationError( + 'MPTokenIssuanceCreate: MutableFlags out of range (must be 0..0xFFFFFFFF)', + ) + } + }packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (2)
176-179: Tighten types: integer-only for MutableFlagsSame as Create: MutableFlags should be finite UInt32.
Apply this diff:
- validateOptionalField(tx, 'MutableFlags', isNumber) + validateOptionalField(tx, 'MutableFlags', isInteger) + if (typeof tx.MutableFlags === 'number') { + if (tx.MutableFlags < 0 || tx.MutableFlags > 0xffffffff) { + throw new ValidationError( + 'MPTokenIssuanceSet: MutableFlags out of range (must be 0..0xFFFFFFFF)', + ) + } + }
197-203: Minor: enforce integer TransferFeeServer expects integral steps; guard against decimals/NaN.
Apply this diff:
if (typeof tx.TransferFee === 'number') { + if (!Number.isFinite(tx.TransferFee) || !Number.isInteger(tx.TransferFee)) { + throw new ValidationError('MPTokenIssuanceSet: TransferFee must be a finite integer') + } if (tx.TransferFee < 0 || tx.TransferFee > MAX_TRANSFER_FEE) { throw new ValidationError( `MPTokenIssuanceSet: TransferFee must be between 0 and ${MAX_TRANSFER_FEE}`, ) } }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts(5 hunks)packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts(7 hunks)packages/xrpl/test/models/MPTokenIssuanceSet.test.ts(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/xrpl/test/models/MPTokenIssuanceSet.test.ts
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:57-64
Timestamp: 2025-09-16T05:00:20.389Z
Learning: In XRPL's MPTokenIssuanceCreate flags, the tfMPTCanMutate* flags intentionally use the same bit values as their corresponding base flags (e.g., tfMPTCanMutateCanLock = 0x00000002 matches tfMPTCanLock = 0x00000002) because they operate in different contexts - base flags go in the Flags field while mutable flags go in the MutableFlags field. This design avoids ambiguity since the flags are applied to separate bit fields.
📚 Learning: 2025-09-16T05:00:20.389Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:57-64
Timestamp: 2025-09-16T05:00:20.389Z
Learning: In XRPL's MPTokenIssuanceCreate flags, the tfMPTCanMutate* flags intentionally use the same bit values as their corresponding base flags (e.g., tfMPTCanMutateCanLock = 0x00000002 matches tfMPTCanLock = 0x00000002) because they operate in different contexts - base flags go in the Flags field while mutable flags go in the MutableFlags field. This design avoids ambiguity since the flags are applied to separate bit fields.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.tspackages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2024-12-06T18:44:55.095Z
Learnt from: shawnxie999
PR: XRPLF/xrpl.js#2661
File: packages/xrpl/test/models/MPTokenAuthorize.test.ts:60-71
Timestamp: 2024-12-06T18:44:55.095Z
Learning: In the XRPL.js library's TypeScript test file `packages/xrpl/test/models/MPTokenAuthorize.test.ts`, negative test cases for invalid `Account` address format, invalid `Holder` address format, invalid `MPTokenIssuanceID` format, and invalid flag combinations are not necessary.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.tspackages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2024-12-05T16:48:12.951Z
Learnt from: achowdhry-ripple
PR: XRPLF/xrpl.js#2661
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:69-102
Timestamp: 2024-12-05T16:48:12.951Z
Learning: When adding validation in `validate*` functions in `packages/xrpl/src/models/transactions/`, utilize existing helper functions (e.g., `validateOptionalField`, `validateType`, `isNumber`, `isInteger`) for type checking and validation where appropriate.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.tspackages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-01-08T13:08:52.688Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2873
File: packages/xrpl/src/models/transactions/trustSet.ts:33-36
Timestamp: 2025-01-08T13:08:52.688Z
Learning: For trust-set transactions in XRPL, validation rules for flags should be implemented comprehensively rather than cherry-picking specific rules, as there are many interdependent validation rules associated with these flags.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.tspackages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
🧬 Code graph analysis (2)
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (4)
packages/xrpl/src/models/transactions/common.ts (4)
validateOptionalField(412-432)isString(141-143)isNumber(151-153)MAX_MPT_META_BYTE_LENGTH(26-26)packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
MAX_TRANSFER_FEE(19-19)packages/xrpl/src/errors.ts (1)
ValidationError(156-156)packages/xrpl/src/models/utils/index.ts (1)
isHex(60-62)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
packages/xrpl/src/models/transactions/common.ts (2)
validateOptionalField(412-432)isNumber(151-153)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: browser (22.x)
- GitHub Check: unit (20.x)
- GitHub Check: unit (22.x)
- GitHub Check: integration (20.x)
- GitHub Check: integration (22.x)
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (6)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (2)
19-19: Good: centralize the TransferFee limitExporting MAX_TRANSFER_FEE for reuse is the right move and avoids magic numbers across transactions.
140-142: Confirm: Should MPTokenIssuanceCreate accept MutableFlags?Spec-wise, MutableFlags typically belong to the Set transaction. If Create does not support it on-ledger, keeping it in the interface may confuse users or produce invalid tx blobs.
Would you like me to remove MutableFlags from Create, or document explicitly that it’s ignored by rippled on Create?
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (4)
17-18: Good reuse: import MAX_TRANSFER_FEEAvoids duplication and keeps fee limits consistent with Create.
90-141: Potential confusion: booleans for MutableFlags are on Flags interfaceMPTokenIssuanceSetFlagsInterface includes tfMPTSet*/tfMPTClear* booleans (which belong to MutableFlags). Verify the builder splits these into tx.MutableFlags and does not place them under tx.Flags.
If splitting isn’t implemented, I can propose a minimal helper to compute both fields from the interface.
161-164: LGTM: new optional fields are addedPublic surface matches spec additions.
33-81: Clarify separation: these flags must end up in MutableFlags, not FlagsMPTokenIssuanceSetFlagsInterface includes both regular and "Set/Clear" mutable booleans, but I didn't find code that converts those mutable booleans into tx.MutableFlags during serialization; tests set MutableFlags as a numeric value. Verify that callers/serialization (e.g. setTransactionFlagsToNumber / convertTxFlagsToNumber / client.autofill) map the tfMPTSet*/tfMPTClear* booleans into MutableFlags, or require callers to pass MutableFlags numerically.
Relevant locations: packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts, packages/xrpl/src/models/utils/flags.ts (setTransactionFlagsToNumber / convertTxFlagsToNumber / parseTransactionFlags), and tests under packages/xrpl/test/models/MPTokenIssuanceSet.test.ts and packages/xrpl/test/integration/transactions/mptokenIssuanceSet.test.ts.
|
I'm working on fixing the integration and browser tests, however I'd love to get a round of code-reviews. I'm not entirely sure why the integ-tests are not connecting to the local rippled standalone instance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
.github/workflows/nodejs.yml(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:57-64
Timestamp: 2025-09-16T05:00:20.420Z
Learning: In XRPL's MPTokenIssuanceCreate flags, the tfMPTCanMutate* flags intentionally use the same bit values as their corresponding base flags (e.g., tfMPTCanMutateCanLock = 0x00000002 matches tfMPTCanLock = 0x00000002) because they operate in different contexts - base flags go in the Flags field while mutable flags go in the MutableFlags field. This design avoids ambiguity since the flags are applied to separate bit fields.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: unit (22.x)
- GitHub Check: build-and-lint (22.x)
- GitHub Check: unit (20.x)
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
.github/workflows/nodejs.yml (1)
221-230: DRY & replace presence-only Docker check with health-based waitReplace the step in .github/workflows/nodejs.yml (around lines 221–230) with the health-wait below and extract it to .github/actions/wait-for-rippled; call that action from other jobs (e.g., any browser/integration jobs) to avoid flakes.
- - name: Check if Docker container is running - run: | - docker ps - docker ps -a - docker inspect rippled-service - if ! docker ps | grep -q rippled-service; then - echo "rippled-service Docker container is not running" - exit 1 - fi + - name: Wait for rippled-service to be healthy + run: | + set -Eeuo pipefail + if ! docker ps --filter 'name=^/rippled-service$' --format '{{.Names}}' | grep -qx rippled-service; then + echo "rippled-service container not found." + docker ps -a || true + exit 1 + fi + for i in {1..40}; do + status="$(docker inspect -f '{{.State.Health.Status}}' rippled-service || echo unknown)" + echo "Attempt $i: health=$status" + [ "$status" = "healthy" ] && break || sleep 3 + done + if [ "${status:-unknown}" != "healthy" ]; then + echo "::error::rippled-service failed to become healthy." + docker inspect -f '{{json .State.Health}}' rippled-service || true + docker logs --tail 200 rippled-service || true + exit 1 + fi
| - name: Check if Docker container is running | ||
| run: | | ||
| docker ps | ||
| docker ps -a | ||
| docker inspect rippled-service | ||
| if ! docker ps | grep -q rippled-service; then | ||
| echo "rippled-service Docker container is not running" | ||
| exit 1 | ||
| fi | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Wait for rippled to be healthy, not merely “running”.
The grep on docker ps only checks container presence and can pass while health is starting/unhealthy, which matches the author’s symptom (“integration tests not connecting”). Poll the container health and surface logs on failure.
Apply this diff to replace the step with a health-aware wait + diagnostics:
- - name: Check if Docker container is running
- run: |
- docker ps
- docker ps -a
- docker inspect rippled-service
- if ! docker ps | grep -q rippled-service; then
- echo "rippled-service Docker container is not running"
- exit 1
- fi
+ - name: Wait for rippled-service to be healthy
+ run: |
+ set -Eeuo pipefail
+ echo "Checking rippled-service container existence..."
+ if ! docker ps --filter 'name=^/rippled-service$' --format '{{.Names}}' | grep -qx rippled-service; then
+ echo "rippled-service container not found in running containers."
+ docker ps -a || true
+ exit 1
+ fi
+ echo "Waiting for rippled-service (health=healthy)..."
+ for i in {1..40}; do
+ status="$(docker inspect -f '{{.State.Health.Status}}' rippled-service || echo unknown)"
+ echo "Attempt $i: health=$status"
+ if [ "$status" = "healthy" ]; then
+ echo "rippled-service is healthy."
+ break
+ fi
+ sleep 3
+ done
+ if [ "${status:-unknown}" != "healthy" ]; then
+ echo "::error::rippled-service failed to become healthy in time."
+ echo "=== docker ps ==="
+ docker ps -a || true
+ echo "=== inspect (Health) ==="
+ docker inspect -f '{{json .State.Health}}' rippled-service || true
+ echo "=== last 200 logs ==="
+ docker logs --tail 200 rippled-service || true
+ exit 1
+ fiOptional follow-up outside this hunk: make container teardown non-fatal to avoid masking earlier failures.
# change step "Stop docker container"
run: docker stop rippled-service || trueTo verify, re-run the workflow; the step should show “health=healthy” before tests start. If it times out, the emitted logs will pinpoint why rippled isn’t ready.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "PWD: $(pwd)"
echo "Searching for workflow file and snippet..."
rg -n --hidden --glob '!node_modules' 'Check if Docker container is running' || true
echo "Check for .github/workflows/nodejs.yml existence..."
if [ -f .github/workflows/nodejs.yml ]; then
echo ".github/workflows/nodejs.yml found; printing lines 140-180:"
nl -ba .github/workflows/nodejs.yml | sed -n '140,180p'
else
echo ".github/workflows/nodejs.yml not found; searching for nodejs.yml and docker inspect usage..."
rg -n --hidden --glob '!node_modules' 'nodejs.yml|docker inspect|rippled-service' || true
fiLength of output: 368
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE='.github/workflows/nodejs.yml'
echo "PWD: $(pwd)"
if [ -f "$FILE" ]; then
echo "$FILE exists; size: $(stat -c%s "$FILE" || true) bytes"
echo "---- lines 150-170 ----"
sed -n '150,170p' "$FILE" || true
echo "---- lines 156-166 ----"
sed -n '156,166p' "$FILE" || true
echo "---- search for keywords in file ----"
if command -v rg >/dev/null 2>&1; then
rg -n 'rippled-service|Check if Docker container is running|Wait for rippled-service' "$FILE" || true
else
grep -nE 'rippled-service|Check if Docker container is running|Wait for rippled-service' "$FILE" || true
fi
else
echo "$FILE not found; searching repo for matches"
if command -v rg >/dev/null 2>&1; then
rg -n 'rippled-service|docker inspect|Check if Docker container is running' || true
else
grep -RIn --exclude-dir=node_modules -E 'rippled-service|docker inspect|Check if Docker container is running' . || true
fi
fiLength of output: 2336
Wait for rippled-service to be healthy, not just running
The current step only checks container presence; it can pass while health is "starting"/"unhealthy", causing integration tests to fail—poll .State.Health and surface logs on timeout.
Location: .github/workflows/nodejs.yml — replace the step at lines 156–166 (duplicate at 221–227).
- - name: Check if Docker container is running
- run: |
- docker ps
- docker ps -a
- docker inspect rippled-service
- if ! docker ps | grep -q rippled-service; then
- echo "rippled-service Docker container is not running"
- exit 1
- fi
+ - name: Wait for rippled-service to be healthy
+ run: |
+ set -Eeuo pipefail
+ echo "Checking rippled-service container existence..."
+ if ! docker ps --filter 'name=^/rippled-service$' --format '{{.Names}}' | grep -qx rippled-service; then
+ echo "rippled-service container not found in running containers."
+ docker ps -a || true
+ exit 1
+ fi
+ echo "Waiting for rippled-service (health=healthy)..."
+ for i in {1..40}; do
+ status="$(docker inspect -f '{{.State.Health.Status}}' rippled-service || echo unknown)"
+ echo "Attempt $i: health=$status"
+ if [ "$status" = "healthy" ]; then
+ echo "rippled-service is healthy."
+ break
+ fi
+ sleep 3
+ done
+ if [ "${status:-unknown}" != "healthy" ]; then
+ echo "::error::rippled-service failed to become healthy in time."
+ echo "=== docker ps ==="
+ docker ps -a || true
+ echo "=== inspect (Health) ==="
+ docker inspect -f '{{json .State.Health}}' rippled-service || true
+ echo "=== last 200 logs ==="
+ docker logs --tail 200 rippled-service || true
+ exit 1
+ fiOptional operational change: make teardown non-fatal to avoid masking earlier failures — change any run: docker stop rippled-service to run: docker stop rippled-service || true (lines ~172 and ~236).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not useful to poll for the existence of the rippled docker container. If the docker container failed to start-up correctly, there is no chance for it to restart in a healthy manner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ckeshava You're absolutely right that polling won't help a failed container restart. I think there was a misunderstanding in my suggestion - I wasn't proposing to restart failed containers, but rather to wait for an already-started container to reach "healthy" status before running tests.
However, since you've identified that as unnecessary, let me suggest a simpler diagnostic approach that might help identify why integration tests aren't connecting:
- - name: Check if Docker container is running
- run: |
- docker ps
- docker ps -a
- docker inspect rippled-service
- if ! docker ps | grep -q rippled-service; then
- echo "rippled-service Docker container is not running"
- exit 1
- fi
+ - name: Check rippled-service connectivity
+ run: |
+ docker ps
+ if ! docker ps | grep -q rippled-service; then
+ echo "rippled-service container not found"
+ docker ps -a
+ exit 1
+ fi
+ echo "Testing rippled connectivity on port 6006..."
+ curl -f http://localhost:6006 || {
+ echo "Failed to connect to rippled on port 6006"
+ docker logs --tail 50 rippled-service
+ exit 1
+ }This approach simply verifies the service is actually accessible on the expected port and shows logs if it's not, which should help diagnose the connection issues without unnecessary waiting.
✏️ Learnings added
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: .github/workflows/nodejs.yml:157-168
Timestamp: 2025-09-22T20:30:43.864Z
Learning: ckeshava prefers not to poll for Docker container health status in CI workflows, believing that failed containers won't recover through polling.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to test the curl command? If the docker ps response does not list the rippled-service container, why do I need other ways to detect the existence of the container?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ckeshava You're absolutely right - if docker ps shows the rippled-service container is running, that should be sufficient to confirm it exists and is operational.
The curl test was intended to distinguish between "container exists" and "service is accessible," which could help diagnose cases where the container runs but the rippled process inside has issues or port mapping failed. However, you make a valid point that this adds unnecessary complexity.
If docker ps confirms the container is running, the integration tests should be able to connect. If they still can't connect despite the container being present, that would likely indicate a different issue (network configuration, test setup, etc.) that wouldn't be solved by additional container checks.
Your current approach of simply verifying container presence with docker ps and failing fast if it's not there is the most straightforward solution.
・゚✧*:・゚✧
🐰 ( curious )
∪ ∪
🧠 Learnings used
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: .github/workflows/nodejs.yml:157-168
Timestamp: 2025-09-22T20:30:43.864Z
Learning: ckeshava prefers not to poll for Docker container health status in CI workflows, believing that failed containers won't recover through polling.
| tfMPTCanTransfer?: boolean | ||
| tfMPTCanClawback?: boolean | ||
|
|
||
| tmfMPTCanMutateCanLock?: boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These flags are only available for MutableFlags field. Should it be separated into its own interface, similar to what we did with SetFlag options in AccountSet?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The flags associated with Dynamic MPTs have
tmf...in their prefix. This is used to indicatetransaction-mutable-flag. This difference in names (tf...versustmf...) should help users differentiate between the intent behind the flags. - If we use a separate interface for these flags, it could potentially cause confusion. The xrpl.org documentation (and the rippled cpp code, other programming language clients) organize these flags under the
MPTokenIssuanceCreatetransaction's flags. This change would have been more impactful if it was done at the XLS level, instead of only xrpl.js deviating from the specification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The xrpl.org documentation (and the rippled cpp code, other programming language clients) organize these flags under the MPTokenIssuanceCreate transaction's flags
Is the xrpl.org documentation updated already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the XLS specification is a good source of info for unreleased amendments. Usually, you can find the pre-release documentation for amendments on https://opensource.ripple.com/ as well, however LendingProtocol docs have not been published yet. You can look at pre-release docs for other amendments on that website.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were separating the flags that can be set with Flags and SetFlags for AccountSet transactions:
https://github.com/XRPLF/xrpl.js/blob/main/packages/xrpl/src/models/transactions/accountSet.ts
I think it's clearer that way, and also allows users to distinguish which flags they can set with Flags and MutableFlags. With this setup user can set a mutable flag with Flags field and there will be no warning, so I think it's more confusing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
.github/workflows/nodejs.yml(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:57-64
Timestamp: 2025-09-16T05:00:20.420Z
Learning: In XRPL's MPTokenIssuanceCreate flags, the tfMPTCanMutate* flags intentionally use the same bit values as their corresponding base flags (e.g., tfMPTCanMutateCanLock = 0x00000002 matches tfMPTCanLock = 0x00000002) because they operate in different contexts - base flags go in the Flags field while mutable flags go in the MutableFlags field. This design avoids ambiguity since the flags are applied to separate bit fields.
📚 Learning: 2025-09-22T20:30:43.864Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: .github/workflows/nodejs.yml:157-168
Timestamp: 2025-09-22T20:30:43.864Z
Learning: ckeshava prefers not to poll for Docker container health status in CI workflows, believing that failed containers won't recover through polling.
Applied to files:
.github/workflows/nodejs.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: unit (22.x)
- GitHub Check: integration (22.x)
- GitHub Check: integration (20.x)
- GitHub Check: unit (20.x)
- GitHub Check: browser (22.x)
- GitHub Check: build-and-lint (22.x)
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: semgrep-cloud-platform/scan
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
complete
|
@Patel-Raj11 The relevant tests in Github CI have passed. |
| tfMPTCanTransfer?: boolean | ||
| tfMPTCanClawback?: boolean | ||
|
|
||
| tmfMPTCanMutateCanLock?: boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The xrpl.org documentation (and the rippled cpp code, other programming language clients) organize these flags under the MPTokenIssuanceCreate transaction's flags
Is the xrpl.org documentation updated already?
|
|
||
| assertInvalid(invalid, 'MPTokenIssuanceSet: flag conflict') | ||
| }) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we usually write tests for all the failure conditions mentioned in the standard, e.g., https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0094-dynamic-MPT#42-failure-conditions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can only check for tem error codes, we cannot validate the other failure cases without reading the state of the blockchain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right — in this case, should we test all the tem failure conditions? If we haven’t done that before, should we start? I agree we don’t need to be exhaustive in integration tests, but for unit tests, I don’t see why not — especially since the spec developer has already listed the conditions for us. We could even use AI to translate them into tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presently, I have not written validations for all the possible failure cases (tem codes). That is a prerequisite for writing unit tests.
I'm not convinced that any validation is required from the client libraries at all. If there is an error in the transaction, it will be failed by rippled with the appropriate error code. The basic validation of the transaction occurs with minimal network overhead, i.e. transactions which fail with a tem code are never "gossip"ed by the XRPL network. What are we gaining by implementing these exhaustive validations in the client libraries?
This is a repetition of engineering effort across three teams. The rippled cpp binary already implements validations+unit-tests for the tem codes. We will be duplicating the code in Transactor::preflight method for each transaction, in all the client libraries. Furthermore, I'm given to understand that the QA team also performs exhaustive tests of a new amendment.
Lastly, The existing set of ~70 transactions do not have exhaustive validations/unit-tests. Are we planning to extend this idea to the other transactions as well? Older transactions like Payment and TrustSet are used a lot more frequently than the other transactions. Hence, validations+unit-tests on older transactions provide the most exposure to the users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on your argument, should we stop writing unit tests for our client libraries just because other teams are already doing so? That doesn’t sound like a good idea. If we shouldn’t stop, then what should our unit tests focus on — the failure conditions that are easier to test or write? Maybe you could elaborate on what you chose to unit test or integration test in this PR and the reasons?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a repetition of engineering effort across three teams. The rippled cpp binary already implements validations+unit-tests for the tem codes. We will be duplicating the code in Transactor::preflight method for each transaction, in all the client libraries. Furthermore, I'm given to understand that the QA team also performs exhaustive tests of a new amendment.
To be clear, my main concern isn’t about unit testing every failure condition — it’s about ensuring we have the right validations in our model objects to prevent obvious failure conditions on the client side. The tem failure conditions listed in the spec seem like a solid reference, which is why I think we should have proper validations or tests covering them, instead of relying on developers to pick and choose which cases to test based on personal judgment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on your argument, should we stop writing unit tests for our client libraries just because other teams are already doing so?
that is my personal opinion, yes.
The USP of the client libraries is the autofill feature, the serializability of transaction, the ease of communicating with the XRPL blockchain. I feel we shouldn't duplicate the engineering effort of testing for the correctness of transactions in both rippled-cpp-code and all the client libraries (py, js, java, go).
Although I disagree with you, I can write more tests for the failure modes of DynamicMPT amendment in the next few days, I understand the benefit of your suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @ckeshava! I’ll add this as a topic for our next sprint retro and see what the rest of the team thinks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added all the validations and unit tests for the MPTokenIssuance{Create, Set} transactions. Please refer to this commit: 7260f2f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I will review it again today.
…ate/Set) transaction
…736b16c909da7d19fdc7d19b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
packages/xrpl/src/models/ledger/MPTokenIssuance.ts(1 hunks)packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts(6 hunks)packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts(7 hunks)packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts(3 hunks)packages/xrpl/test/models/MPTokenIssuanceSet.test.ts(3 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-09-16T05:00:20.420Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:57-64
Timestamp: 2025-09-16T05:00:20.420Z
Learning: In XRPL's MPTokenIssuanceCreate flags, the tfMPTCanMutate* flags intentionally use the same bit values as their corresponding base flags (e.g., tfMPTCanMutateCanLock = 0x00000002 matches tfMPTCanLock = 0x00000002) because they operate in different contexts - base flags go in the Flags field while mutable flags go in the MutableFlags field. This design avoids ambiguity since the flags are applied to separate bit fields.
Applied to files:
packages/xrpl/src/models/ledger/MPTokenIssuance.tspackages/xrpl/test/models/MPTokenIssuanceCreate.test.tspackages/xrpl/src/models/transactions/MPTokenIssuanceSet.tspackages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-01-08T02:12:28.489Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2874
File: packages/xrpl/test/integration/transactions/permissionedDomain.test.ts:25-80
Timestamp: 2025-01-08T02:12:28.489Z
Learning: For PermissionedDomain feature (XLS-80d), complex error cases like invalid credential format, duplicate credentials, and non-existent DomainID are tested in the rippled C++ implementation rather than being duplicated across SDK implementations like xrpl.js.
Applied to files:
packages/xrpl/src/models/ledger/MPTokenIssuance.ts
📚 Learning: 2024-12-06T18:44:55.095Z
Learnt from: shawnxie999
PR: XRPLF/xrpl.js#2661
File: packages/xrpl/test/models/MPTokenAuthorize.test.ts:60-71
Timestamp: 2024-12-06T18:44:55.095Z
Learning: In the XRPL.js library's TypeScript test file `packages/xrpl/test/models/MPTokenAuthorize.test.ts`, negative test cases for invalid `Account` address format, invalid `Holder` address format, invalid `MPTokenIssuanceID` format, and invalid flag combinations are not necessary.
Applied to files:
packages/xrpl/test/models/MPTokenIssuanceCreate.test.tspackages/xrpl/test/models/MPTokenIssuanceSet.test.ts
📚 Learning: 2025-01-31T17:46:25.375Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2873
File: packages/xrpl/test/integration/transactions/trustSet.test.ts:0-0
Timestamp: 2025-01-31T17:46:25.375Z
Learning: For the XRPL implementation, extensive test cases for deep freeze behavior (high/low side interactions, clearing flags, etc.) are maintained in the C++ implementation and don't need to be duplicated in the JavaScript implementation.
Applied to files:
packages/xrpl/test/models/MPTokenIssuanceSet.test.ts
📚 Learning: 2025-01-08T13:08:52.688Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2873
File: packages/xrpl/src/models/transactions/trustSet.ts:33-36
Timestamp: 2025-01-08T13:08:52.688Z
Learning: For trust-set transactions in XRPL, validation rules for flags should be implemented comprehensively rather than cherry-picking specific rules, as there are many interdependent validation rules associated with these flags.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
🧬 Code graph analysis (4)
packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts (1)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
tmfMPTokenIssuanceCreateMutableMask(92-101)
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (4)
packages/xrpl/src/models/transactions/common.ts (4)
validateOptionalField(426-446)isString(146-148)isNumber(156-158)MAX_MPT_META_BYTE_LENGTH(26-26)packages/xrpl/src/errors.ts (1)
ValidationError(156-156)packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
MAX_TRANSFER_FEE(19-19)packages/xrpl/src/models/utils/index.ts (1)
isHex(60-62)
packages/xrpl/test/models/MPTokenIssuanceSet.test.ts (3)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
MAX_TRANSFER_FEE(19-19)packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (1)
tmfMPTokenIssuanceSetMutableMask(60-73)packages/xrpl/src/models/transactions/common.ts (1)
MAX_MPT_META_BYTE_LENGTH(26-26)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (3)
packages/xrpl/src/models/transactions/metadata.ts (1)
TransactionMetadataBase(84-93)packages/xrpl/src/models/transactions/common.ts (2)
validateOptionalField(426-446)isNumber(156-158)packages/xrpl/src/errors.ts (1)
ValidationError(156-156)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: browser (22.x)
- GitHub Check: build-and-lint (22.x)
- GitHub Check: integration (20.x)
- GitHub Check: unit (20.x)
- GitHub Check: unit (22.x)
- GitHub Check: integration (22.x)
🔇 Additional comments (18)
packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts (3)
8-11: LGTM! Test imports are appropriate.The addition of
tmfMPTokenIssuanceCreateMutableMaskimport enables testing of the MutableFlags validation logic introduced in the implementation.
34-34: LGTM! Valid test fixture properly demonstrates MutableFlags usage.The fixture correctly uses
tmfMPTCanMutateTransferFeeto enable mutability for the TransferFee field, which aligns with the Dynamic MPT specification.
149-157: LGTM! Test effectively validates MutableFlags mask enforcement.The test correctly verifies that an invalid MutableFlags value (using the mask itself, which has all valid bits set to 0) is rejected with the appropriate error message.
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (5)
19-19: LGTM! MAX_TRANSFER_FEE export enables consistent validation.Exporting this constant allows reuse in related transactions (e.g., MPTokenIssuanceSet) and ensures consistency across the codebase.
57-89: LGTM! Mutate flags are well-documented and correctly defined.The flag definitions are clear, with documentation explaining each flag's purpose. The intentional reuse of base flag bit values is appropriate since these operate in the separate MutableFlags field context.
Based on learnings.
91-102: LGTM! Mask computation correctly identifies invalid MutableFlags bits.The bitwise NOT operation produces a mask where valid flag bits are 0 and invalid bits are 1, enabling efficient validation via bitwise AND.
225-225: LGTM! MutableFlags field properly extends the transaction interface.The optional field allows specifying which flags can be mutated after issuance creation, aligning with the XLS-94D specification.
247-257: LGTM! MutableFlags validation correctly enforces the mask.The validation logic properly checks that only recognized flag bits are set by testing
MutableFlags & mask. If any invalid bits are set, the result is non-zero and triggers an error.packages/xrpl/test/models/MPTokenIssuanceSet.test.ts (2)
55-60: LGTM! Valid test case demonstrates MutableFlags usage.The test correctly validates that MutableFlags can be used with a clear flag operation, confirming the basic functionality works as expected.
93-191: LGTM! Comprehensive validation test coverage.The test suite thoroughly covers all validation scenarios for the new fields:
- TransferFee: type, lower bound, upper bound
- MutableFlags: type, mask validation
- MPTokenMetadata: type, hex format, length constraints
This ensures the validation logic in MPTokenIssuanceSet.ts is working correctly.
packages/xrpl/src/models/ledger/MPTokenIssuance.ts (3)
14-16: LGTM! Ledger entry fields properly extended for Dynamic MPTs.The addition of
DomainID(optional) andMutableFlags(required) aligns with the rippled implementation and the XLS-94D specification for representing MPTokenIssuance state on the ledger.
18-59: LGTM! Flag interface is comprehensive and well-documented.The interface provides both base flags (lsfMPT*) and mutate capability flags (lsmfMPTCanMutate*), with clear documentation explaining each flag's purpose.
61-102: LGTM! Flag enum correctly defines ledger state flags.The enum properly defines both base flags and mutate capability flags. The intentional reuse of bit values between base and mutate flags is appropriate since they exist in separate fields (Flags vs MutableFlags) on the ledger object.
Based on learnings.
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (5)
2-16: LGTM! Imports properly support new field validations.The added imports (
isHex,isNumber,MAX_MPT_META_BYTE_LENGTH,MAX_TRANSFER_FEE) enable consistent validation across MPTokenIssuance transactions.
33-56: LGTM! Set/Clear flag pattern is well-defined.The 12 MutableFlags follow a consistent Set/Clear pattern for modifying the 6 base capabilities (CanLock, RequireAuth, CanEscrow, CanTrade, CanTransfer, CanClawback). Each flag is clearly documented.
59-74: LGTM! Mask correctly validates MutableFlags combinations.The bitwise NOT of all valid mutate flags produces a mask that efficiently detects invalid flag combinations during validation.
129-131: LGTM! Transaction interface properly extended for Dynamic MPT support.The three optional fields (
MPTokenMetadata,TransferFee,MutableFlags) enable issuers to modify mutable aspects of an MPTokenIssuance after creation, as specified in XLS-94D.
145-189: LGTM! Comprehensive validation for all new fields.The validation logic is thorough and consistent:
- Type validation using
validateOptionalFieldfor all three fields- MutableFlags mask check prevents invalid flag combinations
- TransferFee range enforcement (0 to 50,000)
- MPTokenMetadata hex format and length constraints
All validations follow the same patterns established in MPTokenIssuanceCreate.
| @@ -1,5 +1,12 @@ | |||
| import { stringToHex } from '@xrplf/isomorphic/dist/utils' | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import path inconsistency with MPTokenIssuanceCreate.test.ts.
This file imports from @xrplf/isomorphic/dist/utils while MPTokenIssuanceCreate.test.ts imports from @xrplf/isomorphic/src/utils. For consistency, both test files should use the same import path.
Apply this diff to align with the other test file:
-import { stringToHex } from '@xrplf/isomorphic/dist/utils'
+import { stringToHex } from '@xrplf/isomorphic/src/utils'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { stringToHex } from '@xrplf/isomorphic/dist/utils' | |
| import { stringToHex } from '@xrplf/isomorphic/src/utils' |
🤖 Prompt for AI Agents
In packages/xrpl/test/models/MPTokenIssuanceSet.test.ts around line 1, the
import path uses '@xrplf/isomorphic/dist/utils' which is inconsistent with
MPTokenIssuanceCreate.test.ts that imports from '@xrplf/isomorphic/src/utils';
update the import to use '@xrplf/isomorphic/src/utils' so both tests use the
same source path, and run tests to ensure the module resolves correctly.
| */ | ||
| MPTokenMetadata?: string | ||
|
|
||
| Flags?: number | MPTokenIssuanceCreateFlagsInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flags cannot accept the mutable flags so the above change will be needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code has been changed in ce16616
| export interface MPTokenIssuanceSetFlagsInterface extends GlobalFlagsInterface { | ||
| tfMPTLock?: boolean | ||
| tfMPTUnlock?: boolean | ||
| // The below flags are used in the MutableFlags field |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated in 42049ac
| tfMPTCanTransfer?: boolean | ||
| tfMPTCanClawback?: boolean | ||
|
|
||
| tmfMPTCanMutateCanLock?: boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were separating the flags that can be set with Flags and SetFlags for AccountSet transactions:
https://github.com/XRPLF/xrpl.js/blob/main/packages/xrpl/src/models/transactions/accountSet.ts
I think it's clearer that way, and also allows users to distinguish which flags they can set with Flags and MutableFlags. With this setup user can set a mutable flag with Flags field and there will be no warning, so I think it's more confusing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
289-299: Allow zero for MaximumAmount per XLS-0094
Per XLS-0094,MaximumAmountis an unsigned 64-bit integer (zero permitted). Change the lower-bound check from<= 0to< 0:-} else if ( - BigInt(tx.MaximumAmount) > BigInt(MAX_AMT) || - BigInt(tx.MaximumAmount) <= BigInt(`0`) -) { +} else if ( + BigInt(tx.MaximumAmount) > BigInt(MAX_AMT) || + BigInt(tx.MaximumAmount) < BigInt(0) +) {
♻️ Duplicate comments (1)
packages/xrpl/test/models/MPTokenIssuanceSet.test.ts (1)
1-1: Align import path with other testsUse consistent source import path for isomorphic utils.
-import { stringToHex } from '@xrplf/isomorphic/dist/utils' +import { stringToHex } from '@xrplf/isomorphic/src/utils'
🧹 Nitpick comments (2)
packages/xrpl/src/models/transactions/common.ts (1)
773-779: Revisit DomainID validation scopeAdding isHex + all-zero rejection tightens validation that was previously length-only. This may duplicate codec-level checks and diverge from prior guidance.
Based on learnings
Option to revert to length-only (if desired):
export function isDomainID(domainID: unknown): domainID is string { return ( isString(domainID) && domainID.length === _DOMAIN_ID_LENGTH && - isHex(domainID) && - domainID !== '0'.repeat(_DOMAIN_ID_LENGTH) + true ) }packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (1)
222-247: Minor: avoid per-call allocation of flag pairsHoist MPTMutabilityFlags to a top-level
constto avoid re-allocating on every validation.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts(8 hunks)packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts(7 hunks)packages/xrpl/src/models/transactions/common.ts(1 hunks)packages/xrpl/src/models/utils/flags.ts(1 hunks)packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts(3 hunks)packages/xrpl/test/models/MPTokenIssuanceSet.test.ts(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/xrpl/test/models/MPTokenIssuanceCreate.test.ts
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:57-64
Timestamp: 2025-09-16T05:00:20.420Z
Learning: In XRPL's MPTokenIssuanceCreate flags, the tfMPTCanMutate* flags intentionally use the same bit values as their corresponding base flags (e.g., tfMPTCanMutateCanLock = 0x00000002 matches tfMPTCanLock = 0x00000002) because they operate in different contexts - base flags go in the Flags field while mutable flags go in the MutableFlags field. This design avoids ambiguity since the flags are applied to separate bit fields.
📚 Learning: 2025-09-16T05:00:20.420Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:57-64
Timestamp: 2025-09-16T05:00:20.420Z
Learning: In XRPL's MPTokenIssuanceCreate flags, the tfMPTCanMutate* flags intentionally use the same bit values as their corresponding base flags (e.g., tfMPTCanMutateCanLock = 0x00000002 matches tfMPTCanLock = 0x00000002) because they operate in different contexts - base flags go in the Flags field while mutable flags go in the MutableFlags field. This design avoids ambiguity since the flags are applied to separate bit fields.
Applied to files:
packages/xrpl/src/models/utils/flags.tspackages/xrpl/src/models/transactions/MPTokenIssuanceSet.tspackages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-07-10T22:04:59.994Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3032
File: packages/xrpl/src/models/transactions/common.ts:689-698
Timestamp: 2025-07-10T22:04:59.994Z
Learning: In the XRPL.js library, the validateDomainID function in `packages/xrpl/src/models/transactions/common.ts` should only validate the length (64 characters) of domain IDs, not hex encoding. The rippled C++ implementation does not enforce any regex check on domain ID values, so additional hex validation is not required in the JS implementation.
Applied to files:
packages/xrpl/src/models/transactions/common.ts
📚 Learning: 2025-07-11T21:22:07.809Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3032
File: packages/xrpl/src/models/transactions/common.ts:689-698
Timestamp: 2025-07-11T21:22:07.809Z
Learning: Domain ID validation in XRPL.js is handled at the serialization/deserialization layer through Hash types in the ripple-binary-codec package, not at the transaction validation layer. The validateDomainID function only needs to validate length (64 characters) as hex validation occurs when Hash types are constructed during serialization.
Applied to files:
packages/xrpl/src/models/transactions/common.ts
📚 Learning: 2024-12-06T18:44:55.095Z
Learnt from: shawnxie999
PR: XRPLF/xrpl.js#2661
File: packages/xrpl/test/models/MPTokenAuthorize.test.ts:60-71
Timestamp: 2024-12-06T18:44:55.095Z
Learning: In the XRPL.js library's TypeScript test file `packages/xrpl/test/models/MPTokenAuthorize.test.ts`, negative test cases for invalid `Account` address format, invalid `Holder` address format, invalid `MPTokenIssuanceID` format, and invalid flag combinations are not necessary.
Applied to files:
packages/xrpl/test/models/MPTokenIssuanceSet.test.ts
📚 Learning: 2025-01-31T17:46:25.375Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2873
File: packages/xrpl/test/integration/transactions/trustSet.test.ts:0-0
Timestamp: 2025-01-31T17:46:25.375Z
Learning: For the XRPL implementation, extensive test cases for deep freeze behavior (high/low side interactions, clearing flags, etc.) are maintained in the C++ implementation and don't need to be duplicated in the JavaScript implementation.
Applied to files:
packages/xrpl/test/models/MPTokenIssuanceSet.test.ts
📚 Learning: 2024-12-06T19:25:15.376Z
Learnt from: shawnxie999
PR: XRPLF/xrpl.js#2661
File: packages/xrpl/test/integration/transactions/mptokenAuthorize.test.ts:29-118
Timestamp: 2024-12-06T19:25:15.376Z
Learning: In the XRPLF/xrpl.js TypeScript client library, when writing tests (e.g., in `packages/xrpl/test/integration/transactions/`), we generally do not need to test rippled server behaviors, because those behaviors are covered by rippled's own integration and unit tests.
Applied to files:
packages/xrpl/test/models/MPTokenIssuanceSet.test.ts
📚 Learning: 2025-01-08T13:08:52.688Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2873
File: packages/xrpl/src/models/transactions/trustSet.ts:33-36
Timestamp: 2025-01-08T13:08:52.688Z
Learning: For trust-set transactions in XRPL, validation rules for flags should be implemented comprehensively rather than cherry-picking specific rules, as there are many interdependent validation rules associated with these flags.
Applied to files:
packages/xrpl/test/models/MPTokenIssuanceSet.test.tspackages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
🧬 Code graph analysis (4)
packages/xrpl/src/models/transactions/common.ts (1)
packages/xrpl/src/models/utils/index.ts (1)
isHex(60-62)
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (5)
packages/xrpl/src/models/transactions/common.ts (5)
validateOptionalField(426-446)isString(146-148)isNumber(156-158)isDomainID(773-780)MAX_MPT_META_BYTE_LENGTH(26-26)packages/xrpl/src/models/utils/flags.ts (1)
convertTxFlagsToNumber(105-136)packages/xrpl/src/models/transactions/transaction.ts (1)
Transaction(211-211)packages/xrpl/src/models/utils/index.ts (2)
isFlagEnabled(27-30)isHex(60-62)packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
MAX_TRANSFER_FEE(20-20)
packages/xrpl/test/models/MPTokenIssuanceSet.test.ts (3)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
MAX_TRANSFER_FEE(20-20)packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (1)
tmfMPTokenIssuanceSetMutableMask(67-80)packages/xrpl/src/models/transactions/common.ts (1)
MAX_MPT_META_BYTE_LENGTH(26-26)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (2)
packages/xrpl/src/models/transactions/common.ts (3)
validateOptionalField(426-446)isNumber(156-158)isDomainID(773-780)packages/xrpl/src/models/utils/index.ts (1)
hasFlag(40-52)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: integration (20.x)
- GitHub Check: integration (22.x)
- GitHub Check: unit (20.x)
- GitHub Check: browser (22.x)
- GitHub Check: unit (22.x)
- GitHub Check: build-and-lint (22.x)
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (4)
packages/xrpl/src/models/utils/flags.ts (1)
15-16: Good addition: flag mapping for MPTokenIssuanceSetImport + txToFlag mapping enables consistent flag conversion/parsing for MPTokenIssuanceSet.
Also applies to: 61-61
packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts (1)
66-81: MutableFlags mask approach matches rippled patternUsing a complemented mask to detect out-of-range bits is correct for validating MutableFlags.
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (1)
256-267: DomainID gating on tfMPTRequireAuth looks correctRequiring tfMPTRequireAuth when DomainID is set aligns with intended semantics.
Please confirm this matches rippled preflight for XLS-94D.
packages/xrpl/test/models/MPTokenIssuanceSet.test.ts (1)
46-52: Nice: positive test for valid mutation-only pathCovers the MutableFlags-only scenario well.
| if ( | ||
| (tx.Flags === 0 || tx.Flags === undefined) && | ||
| tx.DomainID == null && | ||
| !isMutate | ||
| ) { | ||
| throw new ValidationError( | ||
| 'MPTokenIssuanceSet: Transaction does not change the state of the MPTokenIssuance ledger object.', | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No-op detection misses object-form Flags (possible false negatives)
Checking tx.Flags === 0 skips cases where Flags is an object with no bits set (converts to 0). Use convertTxFlagsToNumber(tx) to robustly detect no-ops.
Apply:
- if (
- (tx.Flags === 0 || tx.Flags === undefined) &&
- tx.DomainID == null &&
- !isMutate
- ) {
+ if (
+ convertTxFlagsToNumber(tx as Transaction) === 0 &&
+ tx.DomainID == null &&
+ !isMutate
+ ) {
throw new ValidationError(
'MPTokenIssuanceSet: Transaction does not change the state of the MPTokenIssuance ledger object.',
)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if ( | |
| (tx.Flags === 0 || tx.Flags === undefined) && | |
| tx.DomainID == null && | |
| !isMutate | |
| ) { | |
| throw new ValidationError( | |
| 'MPTokenIssuanceSet: Transaction does not change the state of the MPTokenIssuance ledger object.', | |
| ) | |
| } | |
| if ( | |
| convertTxFlagsToNumber(tx as Transaction) === 0 && | |
| tx.DomainID == null && | |
| !isMutate | |
| ) { | |
| throw new ValidationError( | |
| 'MPTokenIssuanceSet: Transaction does not change the state of the MPTokenIssuance ledger object.', | |
| ) | |
| } |
🤖 Prompt for AI Agents
In packages/xrpl/src/models/transactions/MPTokenIssuanceSet.ts around lines 199
to 207, the no-op detection currently checks tx.Flags === 0 which misses cases
where Flags is an object with no bits set; replace the direct check with a
numeric conversion using convertTxFlagsToNumber(tx) (e.g., const flagsNum =
convertTxFlagsToNumber(tx)) and test flagsNum === 0 (or flagsNum === undefined
handling as needed) so the condition reliably detects no-ops for both numeric
and object-form Flags; ensure convertTxFlagsToNumber is imported/available in
the module and update the if condition to use flagsNum instead of tx.Flags.
|
i am trying to complete and send on to yu people it will not allow me |
|
@pdp2121 Please let me know if you have any comments on this PR. |
| MPTokenMetadata?: string | ||
|
|
||
| Flags?: number | MPTokenIssuanceCreateFlagsInterface | ||
| MutableFlags?: number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add docstring for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a recent commit to fix this. However, I could not find the documentation for the domain_id field on the xrpl.org website ://
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: I have added a docstring for the DomainID field as well, based on my understanding of the topic. I could not find any other documentation to that effect. Commit: 0c228cd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Left a small comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts(8 hunks)
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2874
File: packages/xrpl/test/integration/transactions/permissionedDomain.test.ts:25-80
Timestamp: 2025-01-08T02:12:28.489Z
Learning: The rippled C++ implementation (PR #5161) includes comprehensive test coverage for PermissionedDomain (XLS-80d) error cases. The JS SDK tests focus on the happy path since the error cases are already validated at the rippled level, following the principle of not duplicating complex validation testing across SDK implementations.
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:57-64
Timestamp: 2025-09-16T05:00:20.420Z
Learning: In XRPL's MPTokenIssuanceCreate flags, the tfMPTCanMutate* flags intentionally use the same bit values as their corresponding base flags (e.g., tfMPTCanMutateCanLock = 0x00000002 matches tfMPTCanLock = 0x00000002) because they operate in different contexts - base flags go in the Flags field while mutable flags go in the MutableFlags field. This design avoids ambiguity since the flags are applied to separate bit fields.
Learnt from: Patel-Raj11
PR: XRPLF/xrpl.js#3117
File: packages/xrpl/src/models/transactions/common.ts:1133-1180
Timestamp: 2025-10-28T14:16:24.567Z
Learning: The MPTokenMetadata TypeScript interface in xrpl.js reflects the XLS-89 standard (long-form fields only) to provide correct type hints for IDEs and TypeScript users, even though JavaScript users may provide non-standard structures with compact fields or both forms present. This design provides proper tooling support while maintaining runtime flexibility.
Learnt from: Patel-Raj11
PR: XRPLF/xrpl.js#3117
File: packages/xrpl/src/models/transactions/common.ts:1133-1180
Timestamp: 2025-10-28T14:16:24.567Z
Learning: In xrpl.js MPTokenMetadata handling: encodeMPTokenMetadata and decodeMPTokenMetadata are designed to preserve the original structure of the input, only converting between compact and long forms when a single form is present (not both). If both compact (e.g., 'us') and long (e.g., 'uris') forms exist in the input, both are preserved in the output. This is intentional to avoid modifying the user's data. Validation (validateMPTokenMetadata) separately checks and reports XLS-89 compliance.
📚 Learning: 2025-09-16T05:00:20.420Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:57-64
Timestamp: 2025-09-16T05:00:20.420Z
Learning: In XRPL's MPTokenIssuanceCreate flags, the tfMPTCanMutate* flags intentionally use the same bit values as their corresponding base flags (e.g., tfMPTCanMutateCanLock = 0x00000002 matches tfMPTCanLock = 0x00000002) because they operate in different contexts - base flags go in the Flags field while mutable flags go in the MutableFlags field. This design avoids ambiguity since the flags are applied to separate bit fields.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-10-28T14:16:24.567Z
Learnt from: Patel-Raj11
PR: XRPLF/xrpl.js#3117
File: packages/xrpl/src/models/transactions/common.ts:1133-1180
Timestamp: 2025-10-28T14:16:24.567Z
Learning: The MPTokenMetadata TypeScript interface in xrpl.js reflects the XLS-89 standard (long-form fields only) to provide correct type hints for IDEs and TypeScript users, even though JavaScript users may provide non-standard structures with compact fields or both forms present. This design provides proper tooling support while maintaining runtime flexibility.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2024-12-06T18:44:55.095Z
Learnt from: shawnxie999
PR: XRPLF/xrpl.js#2661
File: packages/xrpl/test/models/MPTokenAuthorize.test.ts:60-71
Timestamp: 2024-12-06T18:44:55.095Z
Learning: In the XRPL.js library's TypeScript test file `packages/xrpl/test/models/MPTokenAuthorize.test.ts`, negative test cases for invalid `Account` address format, invalid `Holder` address format, invalid `MPTokenIssuanceID` format, and invalid flag combinations are not necessary.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-10-28T14:16:24.567Z
Learnt from: Patel-Raj11
PR: XRPLF/xrpl.js#3117
File: packages/xrpl/src/models/transactions/common.ts:1133-1180
Timestamp: 2025-10-28T14:16:24.567Z
Learning: In xrpl.js MPTokenMetadata handling: encodeMPTokenMetadata and decodeMPTokenMetadata are designed to preserve the original structure of the input, only converting between compact and long forms when a single form is present (not both). If both compact (e.g., 'us') and long (e.g., 'uris') forms exist in the input, both are preserved in the output. This is intentional to avoid modifying the user's data. Validation (validateMPTokenMetadata) separately checks and reports XLS-89 compliance.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-01-08T13:08:52.688Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2873
File: packages/xrpl/src/models/transactions/trustSet.ts:33-36
Timestamp: 2025-01-08T13:08:52.688Z
Learning: For trust-set transactions in XRPL, validation rules for flags should be implemented comprehensively rather than cherry-picking specific rules, as there are many interdependent validation rules associated with these flags.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2024-12-05T16:48:12.951Z
Learnt from: achowdhry-ripple
PR: XRPLF/xrpl.js#2661
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:69-102
Timestamp: 2024-12-05T16:48:12.951Z
Learning: When adding validation in `validate*` functions in `packages/xrpl/src/models/transactions/`, utilize existing helper functions (e.g., `validateOptionalField`, `validateType`, `isNumber`, `isInteger`) for type checking and validation where appropriate.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-07-10T22:04:59.994Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3032
File: packages/xrpl/src/models/transactions/common.ts:689-698
Timestamp: 2025-07-10T22:04:59.994Z
Learning: In the XRPL.js library, the validateDomainID function in `packages/xrpl/src/models/transactions/common.ts` should only validate the length (64 characters) of domain IDs, not hex encoding. The rippled C++ implementation does not enforce any regex check on domain ID values, so additional hex validation is not required in the JS implementation.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-06-26T17:25:36.429Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3027
File: packages/xrpl/src/models/ledger/MPTokenIssuance.ts:13-16
Timestamp: 2025-06-26T17:25:36.429Z
Learning: In the XRPL ecosystem, type choices for amount fields (like `number` vs `string`) in ledger objects such as `LockedAmount` vs `OutstandingAmount` in `MPTokenIssuance` are deliberate design decisions made across multiple products and cannot be changed unilaterally by individual contributors.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-04-16T15:55:50.121Z
Learnt from: mvadari
PR: XRPLF/xrpl.js#2801
File: packages/xrpl/src/Wallet/batchSigner.ts:0-0
Timestamp: 2025-04-16T15:55:50.121Z
Learning: When using `encodeForSigningBatch` for Batch transactions in the XRPL.js library, the field names should use camelCase (`flags`, `txIDs`) even though the transaction object properties themselves use PascalCase (`Flags`, `TxIDs`).
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-01-31T17:46:25.375Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2873
File: packages/xrpl/test/integration/transactions/trustSet.test.ts:0-0
Timestamp: 2025-01-31T17:46:25.375Z
Learning: For the XRPL implementation, extensive test cases for deep freeze behavior (high/low side interactions, clearing flags, etc.) are maintained in the C++ implementation and don't need to be duplicated in the JavaScript implementation.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-07-11T21:22:07.809Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3032
File: packages/xrpl/src/models/transactions/common.ts:689-698
Timestamp: 2025-07-11T21:22:07.809Z
Learning: Domain ID validation in XRPL.js is handled at the serialization/deserialization layer through Hash types in the ripple-binary-codec package, not at the transaction validation layer. The validateDomainID function only needs to validate length (64 characters) as hex validation occurs when Hash types are constructed during serialization.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
📚 Learning: 2025-01-08T02:12:28.489Z
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2874
File: packages/xrpl/test/integration/transactions/permissionedDomain.test.ts:25-80
Timestamp: 2025-01-08T02:12:28.489Z
Learning: For PermissionedDomain feature (XLS-80d), complex error cases like invalid credential format, duplicate credentials, and non-existent DomainID are tested in the rippled C++ implementation rather than being duplicated across SDK implementations like xrpl.js.
Applied to files:
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
🧬 Code graph analysis (1)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (2)
packages/xrpl/src/models/transactions/common.ts (3)
validateOptionalField(426-446)isNumber(156-158)isDomainID(773-780)packages/xrpl/src/models/utils/index.ts (1)
hasFlag(40-52)
🔇 Additional comments (9)
packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts (9)
2-2: LGTM! New imports support DomainID validation.The
hasFlagandisDomainIDimports are correctly used in the validation logic to check flag requirements and validate the DomainID field format.Also applies to: 14-14
20-20: LGTM! Exporting shared constant.Exporting
MAX_TRANSFER_FEEenables reuse across related transaction types without duplication.
59-92: LGTM! Mutable flags enum is well-documented.The enum correctly defines mutable flags with clear documentation. The
tmfprefix effectively distinguishes these from base transaction flags.Based on learnings: The flag values intentionally match base flag values because they operate in different contexts (Flags vs MutableFlags fields).
94-105: LGTM! Bitmask correctly validates mutable flags.The complement mask computation correctly identifies invalid bits in
MutableFlags. The bitwise operation with eslint suppressions appropriately replicates rippled behavior.
113-144: LGTM! Flag interface now has comprehensive documentation.Each flag property has clear JSDoc comments explaining its purpose, improving developer experience and code maintainability.
146-179: LGTM! Separate mutable flags interface improves clarity.The dedicated interface for mutable flags clearly distinguishes which flags apply to the
MutableFlagsfield versus theFlagsfield, following the pattern established inAccountSet.
231-234: LGTM! New fields properly typed and documented.The
MutableFlagsandDomainIDfields are correctly added as optional number and string types respectively, with an explanatory comment forMutableFlags.
241-242: LGTM! ESLint pragmas accommodate extended validation.The disable/enable comments appropriately suppress line/statement count rules for the expanded validation function.
Also applies to: 342-342
256-280: LGTM! MutableFlags and DomainID validations are comprehensive.The validation logic correctly enforces:
MutableFlagsis a valid number without invalid bits set (using the complement mask)DomainIDis properly formatted (64-char hex, non-zero)DomainIDrequires thetfMPTRequireAuthflag to be setThe use of
hasFlagproperly handles both numeric and object flag formats.
| } else if ( | ||
| BigInt(tx.MaximumAmount) > BigInt(MAX_AMT) || | ||
| BigInt(tx.MaximumAmount) < BigInt(`0`) | ||
| BigInt(tx.MaximumAmount) <= BigInt(`0`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify that MaximumAmount > 0 aligns with XLS-94D.
The validation changed from rejecting negative values to also rejecting zero (<= 0 instead of < 0). While this makes semantic sense (a maximum of 0 tokens is nonsensical), please confirm this stricter requirement is specified in XLS-94D.
🌐 Web query:
Does XLS-94D require MPTokenIssuanceCreate MaximumAmount to be greater than 0?
💡 Result:
Short answer: No.
Reason: MPTokenIssuanceCreate's MaximumAmount is optional and is a uint64. If omitted the implementation treats it as the current default maximum (2^63‑1); you may also set it explicitly (including 0, which would mean no non‑issuer tokens may be minted). (xrpl.org)
Citations:
- 1: https://xrpl.org/docs/references/protocol/transactions/types/mptokenissuancecreate?utm_source=openai
The validation is too strict and conflicts with XLS-94D specification.
According to XLS-94D, MaximumAmount may be explicitly set to 0, which means no non-issuer tokens may be minted. The current validation rejects this valid state. Change the condition from <= 0 to < 0 to allow zero as a valid MaximumAmount value.
🤖 Prompt for AI Agents
In packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts around line
297, the validation currently rejects MaximumAmount when it equals 0 using
BigInt(tx.MaximumAmount) <= BigInt(`0`); update the condition to only reject
negative values by changing the comparison to BigInt(tx.MaximumAmount) <
BigInt(`0`) so that 0 is accepted per XLS-94D.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Fetch the rippled C++ implementation to verify the validation logic
curl -s "https://raw.githubusercontent.com/XRPLF/rippled/f8b4f692f1cb3b971138b71912bcd2c2eb9ee4d5/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.cpp" | sed -n '80,100p'
Length of output: 538
@ckeshava, you're absolutely correct!
I've verified the rippled C++ implementation at the link you provided. Line 90 explicitly shows:
if (maxAmt == 0)
return temMALFORMED;The C++ implementation (which is the authoritative source) clearly rejects MaximumAmount = 0. Your current JavaScript validation using <= 0 is correct and properly matches the rippled behavior.
My earlier suggestion to allow zero was based on the XLS-94D documentation, but the actual implementation in rippled takes precedence. The current code is working as intended.
🐰💡
🧬 Code Graph Analysis Results
[Relevant code snippets to assist with understanding MPTokenIssuanceCreate.ts and the user’s rebuttal reference]
-
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
- Summary: validateMPTokenIssuanceCreate(tx)
- Description: Runtime validation function for an MPTokenIssuanceCreate transaction.
- Parameters: tx - Record<string, unknown> representing the transaction.
- Returns: void (throws ValidationError on malformed input).
- Behavior: Validates base transaction structure, optional fields, DomainID with tfMPTRequireAuth gating, immutable/mutable flags constraints, MaximumAmount format/range, TransferFee range and dependency on tfMPTCanTransfer, optional MPTokenMetadata format and length, and conducts metadata-specific checks via validateMPTokenMetadata when provided. Emits console.warn with MPTTokenMetadata validation messages when non-compliant, but does not fail the transaction solely on metadata structure.
- Errors/Exceptions: Throws ValidationError for malformed fields, missing required gating conditions (e.g., DomainID without tfMPTRequireAuth), invalid MutableFlags, invalid MaximumAmount, invalid TransferFee, or other field format issues.
- Description: Runtime validation function for an MPTokenIssuanceCreate transaction.
- Summary: validateMPTokenIssuanceCreate(tx)
-
File: packages/xrpl/src/models/utils/index.ts
- Snippet: hasFlag
- Location: hasFlag(tx, flag, flagName)
- Content:
- If tx.Flags is null/undefined, returns false.
- If Flags is a number, uses isFlagEnabled to check the numeric flag.
- If Flags is an object, checks tx.Flags[flagName] === true.
- Use: Used by MPTokenIssuanceCreate to determine flag state when Flags is either a numeric bitflag or an object with named booleans.
- Snippet: hasFlag
-
File: packages/xrpl/src/models/utils/index.ts
- Snippet: isHex
- Location: isHex(str)
- Content: Returns true if str matches hex format (via HEX_REGEX).
- Use: Validates hex-encoded fields like MPTokenMetadata hex payload.
- Snippet: isHex
-
File: packages/xrpl/src/models/utils/index.ts
- Snippet: INTEGER_SANITY_CHECK
- Location: INTEGER_SANITY_CHECK
- Content: /^[0-9]+$/u
- Use: Validates numeric strings (e.g., MaximumAmount).
- Snippet: INTEGER_SANITY_CHECK
-
File: packages/xrpl/src/models/utils/index.ts
- Snippet: isFlagEnabled
- Location: isFlagEnabled(Flags, checkFlag)
- Content: Bitwise check returning true if a given flag is set.
- Use: Used to inspect numeric Flags for specific MPTokenIssuanceCreateFlags.
- Snippet: isFlagEnabled
-
File: packages/xrpl/src/models/transactions/common.ts
-
Snippet: BaseTransaction interface (partial)
- Location: BaseTransaction
- Content: Core fields like Account, TransactionType, Fee, Sequence, Memos, Signers, etc.
- Use: Provides the shape that MPTokenIssuanceCreate extends when validating.
-
Snippet: GlobalFlagsInterface
- Location: GlobalFlagsInterface
- Content: tfInnerBatchTxn?: boolean
- Use: Part of the Flags typing for transactions.
-
-
File: packages/xrpl/src/models/transactions/common.ts
- Snippet: validateOptionalField
- Location: validateOptionalField(...)
- Content: Generic helper to validate optional fields with a runtime type guard, throwing ValidationError if the field is present but invalid.
- Use: Used by validateMPTokenIssuanceCreate to validate optional fields like MaximumAmount, MPTokenMetadata, TransferFee, AssetScale, DomainID.
- Snippet: validateOptionalField
-
File: packages/xrpl/src/models/transactions/metadata.ts
- Snippet: TransactionMetadataBase
- Location: TransactionMetadataBase
- Content: AffectedNodes, DeliveredAmount, TransactionIndex, TransactionResult, ParentBatchID, etc.
- Use: Context for transaction metadata in general; relevant for how MPTokenIssuanceCreate metadata might be represented post-issuance.
- Snippet: TransactionMetadataBase
-
File: packages/xrpl/src/models/transactions/common.ts
- Snippet: validateBaseTransaction
- Location: validateBaseTransaction(common)
- Content: Validates core BaseTransaction fields (Account, TransactionType, Fee, Sequence, AccountTxnID, LastLedgerSequence, Memos, Signers, SourceTag, SigningPubKey, TicketSequence, TxnSignature, NetworkID, Delegate) and checks for TransactionType validity and inter-field constraints (e.g., Account and Delegate cannot be the same).
- Use: Called by validateMPTokenIssuanceCreate to ensure the input conforms to the base transaction contract before inspecting MPTokenIssuanceCreate-specific fields.
- Snippet: validateBaseTransaction
-
File: packages/xrpl/src/models/transactions/metadata.ts
- Snippet: MPTokenMetadata validation helper (validateMPTokenMetadata)
- Location: validateMPTokenMetadata(input: string)
- Content: Validates MPTokenMetadata hex payload:
- Checks hex format, length bound (max 1024 bytes), JSON parses to an object, ensures top-level field count, required fields, and validates specific fields (ticker, icon, asset_class, asset_subclass, urls, etc.).
- Returns string[] of validation messages; not thrown, but used by MPTokenIssuanceCreate validation to warn.
- Use: Centralized MPTokenMetadata structural validation used by MPTokenIssuanceCreate.
- Snippet: MPTokenMetadata validation helper (validateMPTokenMetadata)
-
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
- Snippet: MAX_MPT_META_BYTE_LENGTH constant
- Location: MAX_MPT_META_BYTE_LENGTH
- Content: 1024
- Use: Enforces maximum length for MPTokenMetadata hex payload.
- Snippet: MAX_MPT_META_BYTE_LENGTH constant
-
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
- Snippet: MAX_TRANSFER_FEE constant
- Location: MAX_TRANSFER_FEE
- Content: 50000
- Use: Upper bound for TransferFee (0 to 50000).
- Snippet: MAX_TRANSFER_FEE constant
-
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
- Snippet: MPTokenIssuanceCreateFlags enum (brief reference)
- Location: MPTokenIssuanceCreateFlags
- Content: tfMPTCanLock, tfMPTRequireAuth, tfMPTCanEscrow, tfMPTCanTrade, tfMPTCanTransfer, tfMPTCanClawback
- Use: Flag definitions used by validateMPTokenIssuanceCreate to gate behavior (e.g., DomainID requires tfMPTRequireAuth).
- Snippet: MPTokenIssuanceCreateFlags enum (brief reference)
-
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
- Snippet: MPTokenIssuanceCreateMutableFlags enum (brief reference)
- Location: MPTokenIssuanceCreateMutableFlags
- Content: tmfMPTCanMutateCanLock, tmfMPTCanMutateRequireAuth, tmfMPTCanMutateCanEscrow, tmfMPTCanMutateCanTrade, tmfMPTCanMutateCanTransfer, tmfMPTCanMutateCanClawback, tmfMPTCanMutateMetadata, tmfMPTCanMutateTransferFee
- Use: Defines mutable aspects; used to build the mutable mask.
- Snippet: MPTokenIssuanceCreateMutableFlags enum (brief reference)
-
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
- Snippet: tmfMPTokenIssuanceCreateMutableMask
- Location: tmfMPTokenIssuanceCreateMutableMask
- Content: Bitwise NOT mask of all mutable flags that are not allowed to be mutated in this transaction type.
- Use: Compared against tx.MutableFlags to validate mutability.
- Snippet: tmfMPTokenIssuanceCreateMutableMask
-
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
- Snippet: MPTokenIssuanceCreate extends BaseTransaction
- Location: MPTokenIssuanceCreate
- Content: Interface describing fields:
- AssetScale?: number
- MaximumAmount?: string
- TransferFee?: number
- MPTokenMetadata?: string
- Flags?: number | MPTokenIssuanceCreateFlagsInterface
- MutableFlags?: number
- DomainID?: string
- Use: Defines the shape of an MPTokenIssuanceCreate transaction for validation and usage.
- Snippet: MPTokenIssuanceCreate extends BaseTransaction
Notes:
- The user’s link points to a rebuttal in rippled’s MPTokenIssuanceCreate.cpp; the TypeScript implementation here mirrors the validation logic, including constraints around MaximumAmount, TransferFee, MPTokenMetadata, and DomainID gating via tfMPTRequireAuth.
- If you want to map exact behavior from the cited C++ line to this TS code, focus on: DomainID gating, TransferFee validity and dependency on tfMPTCanTransfer, and the MPTokenMetadata format/limits. The provided TS code in validateMPTokenIssuanceCreate implements these areas with corresponding error messages and warning behavior.
✏️ Learnings added
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:298-298
Timestamp: 2025-10-30T12:09:55.768Z
Learning: In XRPL's MPTokenIssuanceCreate transaction validation, MaximumAmount must be greater than 0 (not greater than or equal to). The rippled C++ implementation at MPTokenIssuanceCreate.cpp explicitly rejects MaximumAmount == 0 with temMALFORMED, so the JavaScript validation should use `<= 0` to match this behavior.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: shawnxie999
PR: XRPLF/xrpl.js#2661
File: packages/xrpl/test/models/MPTokenAuthorize.test.ts:60-71
Timestamp: 2024-12-06T18:44:55.095Z
Learning: In the XRPL.js library's TypeScript test file `packages/xrpl/test/models/MPTokenAuthorize.test.ts`, negative test cases for invalid `Account` address format, invalid `Holder` address format, invalid `MPTokenIssuanceID` format, and invalid flag combinations are not necessary.
Learnt from: achowdhry-ripple
PR: XRPLF/xrpl.js#2661
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:69-102
Timestamp: 2024-12-05T16:48:12.951Z
Learning: When adding validation in `validate*` functions in `packages/xrpl/src/models/transactions/`, utilize existing helper functions (e.g., `validateOptionalField`, `validateType`, `isNumber`, `isInteger`) for type checking and validation where appropriate.
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3027
File: packages/xrpl/src/models/ledger/MPTokenIssuance.ts:13-16
Timestamp: 2025-06-26T17:25:36.429Z
Learning: In the XRPL ecosystem, type choices for amount fields (like `number` vs `string`) in ledger objects such as `LockedAmount` vs `OutstandingAmount` in `MPTokenIssuance` are deliberate design decisions made across multiple products and cannot be changed unilaterally by individual contributors.
Learnt from: Patel-Raj11
PR: XRPLF/xrpl.js#3117
File: packages/xrpl/src/models/transactions/common.ts:1133-1180
Timestamp: 2025-10-28T14:16:24.567Z
Learning: The MPTokenMetadata TypeScript interface in xrpl.js reflects the XLS-89 standard (long-form fields only) to provide correct type hints for IDEs and TypeScript users, even though JavaScript users may provide non-standard structures with compact fields or both forms present. This design provides proper tooling support while maintaining runtime flexibility.
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3032
File: packages/xrpl/src/models/transactions/common.ts:689-698
Timestamp: 2025-07-10T22:04:59.994Z
Learning: In the XRPL.js library, the validateDomainID function in `packages/xrpl/src/models/transactions/common.ts` should only validate the length (64 characters) of domain IDs, not hex encoding. The rippled C++ implementation does not enforce any regex check on domain ID values, so additional hex validation is not required in the JS implementation.
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2812
File: packages/xrpl/test/integration/transactions/payment.test.ts:41-43
Timestamp: 2024-10-30T01:05:33.583Z
Learning: In tests involving fee calculations for XRPL, avoid using default fee amounts. If unable to retrieve fee values from the latest validated ledger, throw an error instead of defaulting to a specific amount.
Learnt from: ckeshava
PR: XRPLF/xrpl.js#3081
File: packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts:57-64
Timestamp: 2025-09-16T05:00:20.420Z
Learning: In XRPL's MPTokenIssuanceCreate flags, the tfMPTCanMutate* flags intentionally use the same bit values as their corresponding base flags (e.g., tfMPTCanMutateCanLock = 0x00000002 matches tfMPTCanLock = 0x00000002) because they operate in different contexts - base flags go in the Flags field while mutable flags go in the MutableFlags field. This design avoids ambiguity since the flags are applied to separate bit fields.
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2874
File: packages/xrpl/test/integration/transactions/permissionedDomain.test.ts:25-80
Timestamp: 2025-01-08T02:12:28.489Z
Learning: The rippled C++ implementation (PR #5161) includes comprehensive test coverage for PermissionedDomain (XLS-80d) error cases. The JS SDK tests focus on the happy path since the error cases are already validated at the rippled level, following the principle of not duplicating complex validation testing across SDK implementations.
High Level Overview of Change
Specification is located here: https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0094-dynamic-MPT
CPP implementation can be found here: XRPLF/rippled#5705
Type of Change
Did you update HISTORY.md?
Test Plan
A few unit and integration tests have been added.