Skip to content

feat: Support DynamicMPT (XLS-94) - #1332

Open
pdp2121 wants to merge 22 commits into
mainfrom
dynamic-mpt
Open

pdp2121 wants to merge 22 commits into
mainfrom
dynamic-mpt

Conversation

@pdp2121

@pdp2121 pdp2121 commented Jul 6, 2026 •

Copy link
Copy Markdown
Collaborator

High Level Overview of Change

  • Decode and display the new MutableFlags field on MPTokenIssuanceCreate and the MPTokenIssuance ledger object, plus the new MutableFlags / MPTokenMetadata / TransferFee fields on MPTokenIssuanceSet.
  • MPT token page Settings: shows a Mutable pill on capabilities the issuer can still enabled, hidden once a capability is enabled (capabilities are enable-only in the merged scheme), plus Mutable rows for Metadata and Transfer Fee.

Context of Change

Spec: https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0094-dynamic-MPT
Corresponding merged rippled PRs:

#5705 – Support DynamicMPT XLS-94d (core implementation)
#5797 – Rename mutable flags for DynamicMPT XLS-94d
#5820 – Rename flags for DynamicMPT
#6834 – Fix DynamicMPT for Attackathon
#7439 – Remove clear mutable flags for DynamicMPT XLS-94

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (non-breaking change that only restructures code)
  • Tests (You added tests for code that already exists, or your new feature included in this PR)
  • Documentation Updates
  • Translation Updates
  • Release

Before / After

MPTokenIssuanceCreate — with ImmutableFlags

create_immut

MPTokenIssuanceSet — enable CanEscrow + CanTrade

Screenshot 2026-08-28 at 9 54 15 AM

MPTokenIssuanceSet — update metadata + TransferFee + lock via ImmutableFlags

set_immut

MPT page with new Settings

Screenshot 2026-09-14 at 12 31 58 PM

@kuan121

kuan121 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

This PR needs to be updated to match the latest Dynamic MPT spec and xrpld changes.

Comment thread public/locales/en-US/translations.json Outdated
Comment thread src/containers/shared/components/Transaction/MPTokenIssuanceCreate/parser.ts Outdated
Comment thread src/containers/Token/MPT/Header/Settings.tsx Outdated
Comment thread public/locales/ca-CA/translations.json
Comment thread src/containers/shared/transactionUtils.ts
Comment thread src/containers/Token/MPT/Header/Settings.tsx Outdated
@kuan121

kuan121 commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

/ai-review

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid, well-tested implementation of DynamicMPT (XLS-94) flag decoding and UI surfacing. Two things worth a second look: the TX_FLAGS map for MPTokenIssuanceSet drops the old 0x1000/0x2000 bit mappings entirely rather than keeping them alongside the renamed ones, and the new 'Mutable' pill logic in Settings.tsx wires up immutableFlag for six of the seven capability flags but skips canConfidentialAmount even though a corresponding lsifMPTCanHoldConfidentialBalance bit exists in the immutable-flags map.

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well-structured addition of DynamicMPT (XLS-94) support: new ImmutableFlags decoding on MPTokenIssuanceCreate/MPTokenIssuanceSet/MPTokenIssuance, and a 'Mutable' badge UI in the MPT Settings panel. I cross-checked all the new bit-flag maps (MPT_IMMUTABLE_FLAGS in transactionUtils.ts, MPT_ISSUANCE_IMMUTABLE_FLAGS in rippled/lib/utils.ts, and the immutableFlag wiring in Settings.tsx) against each other and against the new test fixtures/mock data — the bit values and flag names are internally consistent, and the added/updated unit tests match the implemented badge-visibility logic (capability enable-only, badge hidden once enabled or once locked, field rows for Metadata/TransferFee hidden once locked). No correctness, security, or resource-handling bugs found in the changed lines. Two low-confidence/low-value items worth a quick look below.

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid, well-tested implementation of DynamicMPT (XLS-94) decoding and UI. Main finding: the ImmutableFlags bit-to-name mapping is defined twice with parallel but independently-maintained tables (tif* names in transactionUtils.ts and lsif* names in rippled/lib/utils.ts), which is a duplication risk if rippled ever changes/adds a bit value. No correctness or security issues found in the changed lines otherwise.

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The core DynamicMPT decoding/UI logic (immutable flags on MPTokenIssuanceCreate/Set, Settings page badges) looks correct and is well covered by tests. The one thing worth fixing before merge is that the ImmutableFlags bit-to-name tables are duplicated verbatim (same bit values, different name prefixes) across two files instead of being derived from a single source, which the comments themselves acknowledge ("Same bit values as the ledger lsif* map"). Everything else (badge logic, parser wiring, i18n key usage) is consistent with existing patterns.

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid feature addition: decodes MutableFlags/ImmutableFlags on MPTokenIssuanceCreate/Set and the MPTokenIssuance ledger object, and adds a clear Mutable/Immutable UI on the MPT Settings panel. Bit-value mappings for the new capability flags were cross-checked against the Settings component's flag→immutableFlag wiring and all line up correctly (no copy-paste mismatch found). The one thing worth tightening before merge is that the tif*/lsif* immutable-flag bit constants are defined twice in two different files with identical values — a future spec tweak to one map without the other would silently desync ledger-object decoding from transaction decoding.

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lockfile mixed registries will block external contributors — see inline.

Comment thread package-lock.json Outdated

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This MR wires up DynamicMPT (XLS-94) decoding and UI across the MPTokenIssuanceCreate/Set transactions and the MPT ledger object/Settings page. The logic is consistent and well tested (bit values, badge visibility rules, and translations line up correctly across the files I checked). Two things worth a second look before merging: the ImmutableFlags bit-to-name map is now duplicated verbatim in two separate files, and one capability's enabled-flag name doesn't match its immutable-lock-flag name — worth a quick sanity check against the XLS-94 spec/rippled source to make sure that's intentional and not a copy-paste slip.

Comment thread src/containers/shared/components/Transaction/MPTokenIssuanceSet/Simple.tsx Outdated
Comment thread package-lock.json Outdated

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diff adds decoding/display for DynamicMPT (XLS-94) ImmutableFlags/MutableFlags across MPTokenIssuanceCreate, MPTokenIssuanceSet, and the MPT Settings page. The flag-bit maps for tif*/lsif* are consistent with each other and with the test mock data, and the new Settings pill logic (Enabled / Disabled+Mutable / Disabled+Immutable) matches the documented enable-only semantics. Two minor issues worth a look: a type-safety risk from dropping the custom encryption-key type extension in MPTokenIssuanceSet's Simple view, and duplicated immutable-flag bit maps across two files that could drift out of sync over time. The large xrpl/package-lock bump appears justified since changed files directly consume the updated xrpl types (MPTokenIssuanceCreate/Set) needed for the new fields.

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid feature addition wiring up DynamicMPT's MutableFlags/ImmutableFlags decoding and the new mutable/immutable pill UI in Settings.tsx. Two things worth a second look before merge: a naming asymmetry in the new capability→immutableFlag mapping that breaks the otherwise consistent lsf→lsif pattern (possible typo/wrong constant), and a major xrpl dependency version bump that should be confirmed as intentional/required for the new fields rather than an incidental jump.

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a well-structured, thoroughly tested implementation of DynamicMPT (XLS-94) support. I traced the new bit-flag maps (MPT_IMMUTABLE_FLAGS / MPT_ISSUANCE_IMMUTABLE_FLAGS / the new tfMPTSet* capability flags) across transactionUtils.ts, rippled/lib/utils.ts, the MPTokenIssuanceCreate/Set parsers and Simple views, and the Settings component, and the bit values are internally consistent (the ledger lsif*/tx tif* maps intentionally mirror the lsf*/Flags bit positions 1:1, while the Set tfMPTSet* capability flags occupy a separate, non-colliding range in the Flags field). Test coverage for the new Settings pill logic (enabled/disabled/mutable/immutable combinations) and the new Simple-view rows is comprehensive and matches the implementation. The xrpl package major-version bump is directly required by this change (new ImmutableFlags/MutableFlags typings) so it's in-scope, not a stray dependency change. I did not find any correctness, security, or consistency issues in the changed lines that clear the bar for flagging — nothing here looks like a bug likely to bite users in production.

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well-structured feature addition for DynamicMPT (XLS-94). I traced all the new bit-flag maps (MPT_IMMUTABLE_FLAGS in transactionUtils.ts, MPT_ISSUANCE_IMMUTABLE_FLAGS in rippled/lib/utils.ts, and the tfMPTSetCan* capability flags in TX_FLAGS.MPTokenIssuanceSet) against each other and against the new mock-data fixtures — bit values are internally consistent and the test assertions (e.g. 196610 = tifMPTCanLock|tifMPTMetadata|tifMPTTransferFee, 16 = tifMPTCanTrade) check out correctly. The xrpl package bump to ^5.1.0 (and its transitive lockfile churn) is directly required by this change since MPTokenIssuanceSet/MPTokenIssuanceCreate types now need ImmutableFlags/TransferFee/MPTokenMetadata fields, so it's in-scope and not flagged per the dependency-drift rule. The Settings.tsx pill logic (Enabled vs Disabled+Mutable/Immutable) matches the enable-only capability semantics described in the PR, and relative import paths for the newly wired utils/transactionUtils modules resolve correctly. No correctness, security, or resource-leak issues found in the changed lines; the showcase script's hardcoded genesis secret is the well-known public rippled standalone-mode credential, not a real secret.

Comment thread scripts/showcase-dynamic-mpt.mjs Outdated
"confidential": null,
"confidential_outstanding_amount": null,
"holder_encryption_key": null,
"issuer_encryption_key": null,

@kuan121 kuan121 Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you keep the PR description up to date?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the description

Comment on lines -17 to -21
{
key: 'locked',
label: t('locked'),
enabled: flags.includes('lsfMPTLocked'),
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is removed from Settings, but is it added to somewhere else? Simply removing it will be a regression.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added back in 346c1dc

Comment thread src/rippled/lib/utils.ts
parsedMPTMetadata: parseMPTMetadata(rawMPTMetadataHex),
isMPTMetadataCompliant: isMPTMetadataCompliant(rawMPTMetadataHex),
flags: buildFlags(info.Flags, MPT_ISSUANCE_FLAGS),
immutableFlags: buildFlags(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we update unit test to assert those flags as well?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added in 9ae6bd2

Comment thread src/rippled/lib/utils.ts Outdated
const { t } = useTranslation()
const { tooltip, showTooltip, hideTooltip } = useTooltip()

const isLocked = (immutableFlag: string): boolean =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we merge this PR now before DynamicMPT is enabled in mainnet, all the capabilities, transaction fee and metadata will show as mutable. Do we need a gate on amendment activation?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added amendment gating in 37ba377

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DynamicMPT feature implementation (flag decoding, Settings UI, transaction parsers) is internally consistent — the new tif*/lsif* ImmutableFlags bit maps match their own test fixtures, and the xrpl 4.5→5.1 dependency bump is directly justified by the new typed fields (ImmutableFlags, MPTokenMetadata, TransferFee) this PR relies on. The main gap found is a locale-sync inconsistency: the new "active" status string was added to ca-CA/fr-FR/ja-JP/ko-KR but not to es-ES/my-MM, which will leave those two locales showing an untranslated/missing string on the new MPT status row.

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amendment flag logic inverted — see inline.

<Settings
flags={flags}
immutableFlags={immutableFlags}
isDynamicMPTEnabled={!isDynamicMPTEnabled}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amendment gating inverted: isDynamicMPTEnabled is negated before passing to Settings, breaking the feature logic. Remove the negation:

Suggested change
isDynamicMPTEnabled={!isDynamicMPTEnabled}
isDynamicMPTEnabled={isDynamicMPTEnabled}
Suggested change
isDynamicMPTEnabled={!isDynamicMPTEnabled}
isDynamicMPTEnabled={isDynamicMPTEnabled}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9ae6bd2

@ripple-code-reviewer ripple-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a well-executed, consistently implemented feature. The ImmutableFlags/MutableFlags decoding, bit maps (MPT_IMMUTABLE_FLAGS / MPT_ISSUANCE_IMMUTABLE_FLAGS), and the lsfMPTCanConfidentialAmount → lsfMPTCanHoldConfidentialBalance rename were all applied consistently across utils.ts, transactionUtils.ts, Settings.tsx, and the test suites — no stale references or copy-paste mismatches found. The xrpl 4.5.0 → 5.1.0 bump is justified since the new code directly consumes new fields (ImmutableFlags, IssuerEncryptionKey, etc.) from the updated xrpl type defs, and the project's own Node engine requirement (>=22) already exceeds xrpl 5.1's new floor (>=20.19), so no conflict there. Test mock bit-math (e.g. 196610 = 0x2 + 0x10000 + 0x20000) checks out. Only a minor, non-blocking accessibility gap was found in the new tooltip wiring.

@kuan121 kuan121 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Let's ship it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants