Skip to content

feat: add Dynamic MPT support (XLS-0094)#42

Open
Patel-Raj11 wants to merge 5 commits into
mainfrom
feature/DynamicMPT
Open

feat: add Dynamic MPT support (XLS-0094)#42
Patel-Raj11 wants to merge 5 commits into
mainfrom
feature/DynamicMPT

Conversation

@Patel-Raj11

Copy link
Copy Markdown
Owner

References

High Level Overview of Change

Adds SDK support for XLS-0094 DynamicMPT: lets MPT issuers declare a subset of an MPTokenIssuance's capabilities and fields as mutable at creation time, then alter them later via MPTokenIssuanceSet. Without this PR, MPT issuances remain fully immutable post-creation (XLS-0033 default); with it, an issuer can enable previously-dormant capabilities (e.g., lsfMPTCanTransfer, lsfMPTCanClawback) or replace MPTokenMetadata / TransferFee after the fact.

Scope (by category):

  • Transaction modelsMutableFlags added to MPTokenIssuanceCreate; MutableFlags, MPTokenMetadata, and TransferFee added to MPTokenIssuanceSet, introducing a "mutate mode" mutually exclusive with the existing lock/unlock mode.
  • Ledger entry modelsMutableFlags (DEFAULT, UInt32) added to MPTokenIssuance.
  • Flag enums — three new flag enums for the create-side (tmfMPTCanEnable* × 6 + tmfMPTCanMutate{Metadata,TransferFee}), set-side (tmfMPTSet* × 6), and on-ledger (lsmfMPTCanEnable* × 6 + lsmfMPTCanMutate{Metadata,TransferFee}) bit vocabularies.
  • ValidationMutableFlags = 0 and out-of-mask rejection on both transactions; mutate-mode/Holder exclusion; mutate-mode/universal-Flags exclusion; metadata length cap (1024 bytes); transfer-fee cap (50000); pre-emptive refusal of tmfMPTSetCanTransfer paired with non-zero TransferFee in the same tx.
  • Flags handlingconvertTxMutableFlagsToNumber registered alongside the existing tx-flags converter and invoked from both validate() and Client.autofill().
  • Binary codecsfMutableFlags (UInt32, nth=53), MPTokenIssuanceMutable ledger flag enum, and the three updated transaction/ledger formats in ripple-binary-codec's definitions.json.
  • Amendment activationDynamicMPT added to .ci-config/xrpld.cfg so integration tests run against an activated amendment.
  • Tests — unit tests for the new fields, validations, and binary round-trip; integration tests for the end-to-end mutate-mode lifecycles.
  • Docs — HISTORY.md entry under Added.

Context of Change

XLS-0094 is a strictly-additive extension of XLS-0033 MPT: no new transaction types, no new ledger entry types, no new RPC methods, and no new TER codes. The new MutableFlags value flows through the existing MPT RPC surface unchanged, so the work concentrates in models, validation, codec definitions, and tests.

The implementation tracks the final rippled state at SHA 997267f845 (PR #7439, the activating squash). That state diverges from the XLS README in three places (see the "Notes for reviewers" section below). SDK identifiers, mask values, and JSON parsing tables follow rippled, not the pre-redesign XLS vocabulary.

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
  • Release

Did you update HISTORY.md?

  • Yes
  • No, this change does not impact library users

Test Plan

  • Unit tests cover the new MutableFlags field on all three hosts, every validation rule listed in the Scope section (rejection of MutableFlags = 0, out-of-mask bits, Holder in mutate mode, universal-Flags in mutate mode, oversized MPTokenMetadata, oversized TransferFee, and the tmfMPTSetCanTransfer + non-zero TransferFee combination), and binary round-trip of sfMutableFlags on MPTokenIssuanceCreate, MPTokenIssuanceSet, and the MPTokenIssuance ledger entry.
  • Integration tests exercise the four end-to-end flows from the success criteria: the mutable-metadata lifecycle (create → replace → delete), the dormant-capability enable lifecycle across the six toggleable capabilities, the staged CanTransfer enable followed by TransferFee mutation and clearing, and the mutate-permission gating path (a mutating MPTokenIssuanceSet against an issuance that did not declare the corresponding mutability returns tecNO_PERMISSION).
  • All success-criteria items are covered by tests in this PR.

Notes for reviewers

  • Vocabulary divergence from the XLS README. Per rippled PRs #5797, #5820, and #7439, the six toggleable capability flags use CanEnable<Cap> (e.g., tmfMPTCanEnableCanLock, lsmfMPTCanEnableCanLock) rather than the CanMutate<Cap> names in the XLS README; the tmfMPTClear* half of the XLS §4.1 set/clear pairs is gone; and the remaining tmfMPTSet* flags are renumbered to 0x01..0x20. Metadata and TransferFee retain CanMutate on both sides. This SDK matches the rippled final state.
  • Capability enabling is one-way. Once lsfMPTCan<Cap> is set on an issuance — at creation via the tfMPTCan<Cap> create flag, or post-creation via tmfMPTSet<Cap> on MPTokenIssuanceSet — there is no protocol mechanism to clear it. Callers composing a mutating MPTokenIssuanceSet should treat capability enabling as irreversible; downstream UIs may want to surface this affordance.
  • TransferFee mutation requires a staged enable. Setting a non-zero TransferFee on MPTokenIssuanceSet requires lsfMPTCanTransfer to already be set on the issuance; pairing tmfMPTSetCanTransfer and a non-zero TransferFee in the same tx does not satisfy the gate (rippled returns tecNO_PERMISSION). The SDK rejects that combination at validation time to pre-empt obvious-rejection submissions.
  • JSDoc deviations from the change-spec doc strings (cosmetic). A handful of field JSDoc comments add minor clarifying text or use {@link} cross-references in place of section identifiers from the spec. Specifically: MPTokenIssuance.MutableFlags (uses {@link MPTokenIssuanceMutableFlags} and adds a trailing "Absent or 0 means the issuance is fully immutable" sentence), and the MPTokenMetadata / TransferFee fields on MPTokenIssuanceSet (insert the clarifier "on the issuance"). Left as-is on the theory that they are repo-convention enhancements; trivial to revert if the convention is verbatim copy.
  • Resolver-vs-converter duplication (optional cleanup). Per-transaction resolveMPTokenIssuance{Create,Set}MutableFlags helpers duplicate the centralised convertTxMutableFlagsToNumber logic. The centralised converter runs first from validate() / autofill(), so the per-tx resolvers' boolean-interface branch is reachable only when callers invoke the per-tx validators directly. Worth a consolidating refactor later if the conventions allow.

Patel-Raj11 and others added 5 commits June 25, 2026 15:25
* Add DynamicMPT to .ci-config/xrpld.cfg [features] for standalone tests
* Refresh packages/ripple-binary-codec/src/enums/definitions.json from
  rippled (renames lsmf*CanMutate<Cap> -> lsmf*CanEnable<Cap>)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* MPTokenIssuanceCreate: optional MutableFlags (8-bit mask of
  tmfMPTCanEnable<Cap> + tmfMPTCanMutate{Metadata,TransferFee}).
* MPTokenIssuanceSet: optional MutableFlags (6-bit mask of
  tmfMPTSet<Cap>), MPTokenMetadata, TransferFee. Validation enforces
  mutate-mode constraints (no Holder, mutually exclusive with
  lock/unlock) and rejects pairing tmfMPTSetCanTransfer with non-zero
  TransferFee in the same transaction (tecNO_PERMISSION pre-empt).
* MPTokenIssuance ledger entry gains optional MutableFlags and
  MPTokenIssuanceMutableFlags enum.
* utils/flags.ts adds convertTxMutableFlagsToNumber and the
  txToMutableFlag map; autofill() and validate() now resolve the
  MutableFlags interface form to its numeric mask, mirroring how the
  standard Flags field is converted.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds unit tests covering each MutableFlags validation rule on
MPTokenIssuanceCreate and MPTokenIssuanceSet (MutableFlags=0,
out-of-mask bits, mutate-mode Holder ban, lock/unlock vs. mutate-mode
exclusion, MPTokenMetadata / TransferFee bounds, tmfMPTSetCanTransfer
+ non-zero TransferFee gate). Adds binary-codec round-trip cases for
MPTokenIssuanceCreate and MPTokenIssuanceSet exercising the new
MutableFlags field and the empty-blob metadata deletion form.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds dynamicMPT.test.ts covering: MPTokenIssuance creation with
MutableFlags, immutable default when omitted, mutable metadata
lifecycle (replace + delete), dormant-capability enable, staged
CanTransfer enable + TransferFee mutation + clear, mutate-permission
gating returning tecNO_PERMISSION, and a response-type contract
asserting MutableFlags surfaces as a number on the on-ledger
MPTokenIssuance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
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.

1 participant