feat: add Dynamic MPT support (XLS-0094)#42
Open
Patel-Raj11 wants to merge 118 commits into
Open
Conversation
* update HISTORY files * enable SAV amendment * add VaultCreate tx and update autofill * build(deps-dev): bump karma from 6.4.3 to 6.4.4 (XRPLF#2753) * build(deps): bump @scure/bip39 from 1.5.4 to 1.6.0 (XRPLF#3004) * Fix AccountRoot ledger object (XRPLF#3010) * fix AccountRoot ledger object * update HISTORY.md * fix import and lint errors * request a validated ledger * build(deps-dev): bump react from 19.0.0 to 19.1.0 (XRPLF#2968) * upgrade ws dependency (XRPLF#2940) Co-authored-by: achowdhry-ripple <achowdhry@ripple.com> * build(deps-dev): bump webpack from 5.98.0 to 5.99.9 (XRPLF#3015) Bumps [webpack](https://github.com/webpack/webpack) from 5.98.0 to 5.99.9. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](webpack/webpack@v5.98.0...v5.99.9) --- updated-dependencies: - dependency-name: webpack dependency-version: 5.99.9 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: achowdhry-ripple <achowdhry@ripple.com> Co-authored-by: Omar Khan <khancodegt@gmail.com> * add Vault ledger entry and base integ test * add rippled serialized type Number. update models & tests to support it * fix: add conditional check for `PermissionValue` definition (XRPLF#3018) * add conditional check for PermissionValue * update HISTORY * remove release date * add unit test * ripple-binary-codec 2.4.1 patch release (XRPLF#3019) * update HISTORY * update package.json files * update package-lock.json * test: Separate faucet tests from local integration tests (XRPLF#2985) * refactor(tests): separate faucet tests from local integration tests * feat: add Faucet test workflow and documentation * fix: Add missing test:faucet script * fix: execute tests one time Co-authored-by: Raj Patel <rajp@ripple.com> * fix: remove docker steps from faucet test workflow * docs: update faucet tests section in CONTRIBUTING.md * fix: remove comment from contributing.md Co-authored-by: Raj Patel <rajp@ripple.com> * fix: remove test:all from root package Co-authored-by: Raj Patel <rajp@ripple.com> * Update CONTRIBUTING.md --------- Co-authored-by: Raj Patel <rajp@ripple.com> * update number test * debug * set alias Number to SerializedNumber in coreTypes * update fee in VaultCreate integ test * up the fee * up more * debug fee * update fee with comment * add vault_info RPC with integ test * remove unused var in test * use vault_id * update vaultInfo test * add owner and seq params to vault_info request * add DomainID to vault_info response * add XRPLNumber type and VaultSet tx * rename SerializedNumber to XRPLNumber * add VaultSet to integ test * refactor DEFAULT_VAULT_WITHDRAWAL_POLICY location * fix import bug * add VaultDeposit tx * add VaultDeposit to integ test * add VaultWithdraw tx * add VaultWithdraw to integ test * add VaultClawback tx * add VaultClawback to integ test * use 2 wallets for integ test * comment out VaultClawback tx in integ test * use IOU in integ test * add ClawbackAmount type and VaultClawback to integ test * add VaultDelete tx * remove isBigInt * add VaultDelete to integ test * rename to STNumber * comment out Amount in VaultClawback integ test * Revert "comment out Amount in VaultClawback integ test" This reverts commit 416c1e1. * comment out WithdrawalPolicy in VaultCreate integ test * refactor WithdrawalPolicy * cleanup * cleanup vars * update HISTORY * rename var to VAULT_DATA_MAX_BYTE_LENGTH * use STNumber class in static function * add VaultCreate to codec-fixtures * refactor unit tests * update HISTORY --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Raj Patel <rajp@ripple.com> Co-authored-by: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> Co-authored-by: achowdhry-ripple <achowdhry@ripple.com> Co-authored-by: Achal Jhawar <35405812+achaljhawar@users.noreply.github.com>
* generate correct xrpl-latest-min.js file name * remove content of /build in secret-numbers on clean * update HISTORY
…XRPLF#3036) add missing MPTAmount to Vault deposit & withdraw
* XLS-85d: Token Escrow -- Implementation for xrpl.js; This commit includes models, unit-tests and integ-tests for the associated transactions * specify TokenEscrow in the rippled.cfg file * variable renaming in the escrowCreate integ tests * remove references to wallet1 in escrowCreate integ tests * rename useBase10 function as isBase10 method --------- Co-authored-by: Mayukha Vadari <mvadari@gmail.com> Co-authored-by: achowdhry-ripple <achowdhry@ripple.com> Co-authored-by: Omar Khan <khancodegt@gmail.com>
* Implementation of XLS-81d PermissionedDEX; Transaction and Request models are implemented;
fix: weback.test.config.js to webpack.tes.config.js - fix XRPLF#2996 Co-authored-by: Raj Patel <rajp@ripple.com>
* fix: allow DeliverMax in Payment tx * add unit test
…PLF#3050) * introduce hex validation for domainID in Payment, OfferCreate txn * fix: use ==null condition to cover undefined, null and NaN cases * Example snippets file
* add console warnings for incorrect MPTokenMetadata * fix subscribe stream IT due to newly introduced network_id field
* release-xrpl@4.4.0; newer releases for ripple-binary-codec and secret-numbers package * update dependency version numbers of secret-numbers and rbc package * update docs for new release. Note: Documentation is produced by a Gthub Actions CI pipelines. However, this commit ensures that readers of the code-repository use the latest docs. This is required until we completely retire the use of the docs/ folder in this code repository * Revert "update docs for new release. Note: Documentation is produced by a Gthub Actions CI pipelines. However, this commit ensures that readers of the code-repository use the latest docs. This is required until we completely retire the use of the docs/ folder in this code repository" This reverts commit 999132f.
* remove snippets files
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Set up release pipeline as described by RELEASE.md --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…ck (XRPLF#3065) * fix unhandled error and add test case * reduce test time * update HISTORY * assert for trace message
…grep (XRPLF#3069) skip release.yml workflow file itself to prevent false grep search
* update HISTORY.md * release xrpl@4.4.1 * update pacage version in HISTORY.md * Polish wording/capitalization in the 4.4.1 note
…ersion (XRPLF#3075) * Migrate ESLint to v9 and it's related plugins to their latest major version (XRPLF#3075)
Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 9.5.2 to 9.5.4. - [Release notes](https://github.com/TypeStrong/ts-loader/releases) - [Changelog](https://github.com/TypeStrong/ts-loader/blob/main/CHANGELOG.md) - [Commits](TypeStrong/ts-loader@v9.5.2...v9.5.4) --- updated-dependencies: - dependency-name: ts-loader dependency-version: 9.5.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* npm publish with trusted publisher * changes for issue XRPLF#3070 * fix permissions * add the vulnerability report url to the Github issue * fix PR raising for non beta release * do not raise pr for rc/beta release * update RELEASE.md * update release readme * prevent rerun * security enhancement * pin to version for github actions * add additional review/separate review group to prevent approval from the same reviewer
* update package version * update release date --------- Co-authored-by: Raj Patel <rajp@ripple.com>
* WIP commit * WIP commit * fix serialization for Issue * update HISTORY * fix flaking oracle tests * export VaultFlags and some code comments * fix fromParser parsing
* run pipeline from release branch to fix provenance * update release instructions * check branch name at validate input step
Support Node 24 in CI
* refactor: migrate docs generation and publish step into the Release workflow * feat: Introduce conditional trigger of docs generation; Docs are generated only for npm_dist_tag == latest (official non-beta releases) * remove the manual instructions for updating the docs * update the instructions on contributing doc
Co-authored-by: rippled-automation <102213836+rippled-automation@users.noreply.github.com>
… .once() instead of .on() (XRPLF#3211) * prevent 'connected' event listener accumulation on reconnect by using .once() instead of .on() * prevent duplicate event emissions on flaky connections with multiple sequential reconnect attempts * Simplify implementation and add unit test * Fix tests
Bumps [handlebars](https://github.com/handlebars-lang/handlebars.js) from 4.7.8 to 4.7.9. - [Release notes](https://github.com/handlebars-lang/handlebars.js/releases) - [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/v4.7.9/release-notes.md) - [Commits](handlebars-lang/handlebars.js@v4.7.8...v4.7.9) --- updated-dependencies: - dependency-name: handlebars dependency-version: 4.7.9 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This PR includes a few improved validations and bug-fixes. Some of these changes are not warranted by active bugs, rather they are motivated a defense-in-depth perspective. Please read the respective HISTORY.md files for more context of the updates. In addition to the above fixes, this PR also fixes the Github CI setup. The renaming of rippled -> xrpld was blocking the startup of the docker container. This PR updates most of the important references to rippled executable into xrpld.
* fix: change MPTAmount field type from MPTAmount to string * Update History * fix: correct MPTAmount to required field in MPToken interface
Use ed25519 as the default cryptographic signing scheme in xrpl.js sub packages
…RPLF#3231) * feat: add type narrowing for LedgerEntryRequest based on binary flag * fix type error * remove unused import * Add tests for ledger_entry binary param * format and lint * fix format * fix to type import
* chore(deps): quarterly batch dependency upgrade 2026-Q2
…3321) (XRPLF#3331) Client.getServerInfo() previously caught errors from the server_info request and only logged them via console.error, leaving client.networkID undefined. Downstream, txNeedsNetworkID() returned false, so autofill() silently omitted the NetworkID field from signed transactions — making them valid on the wrong network (cross-network replay risk). The method now propagates request errors and additionally throws if the response succeeds without a network_id field. This is a breaking change for clients connecting to rippled <1.11 (which does not return network_id); upgrade rippled or set client.networkID manually. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nal buffer (XRPLF#3319) (XRPLF#3330) * fix(ripple-binary-codec): copy buffer in Amount.toJSON to prevent mutation (XRPLF#3319) The native-XRP branch of Amount.toJSON() aliased this.bytes via `const bytes = this.bytes` and then cleared the type/sign bits with `bytes[0] &= 0x3f`, mutating the SerializedType's internal buffer in place. The first call returned the correct value; subsequent calls and re-serializations produced corrupted output (transaction malleability). Fix by taking a defensive copy with .slice() before masking, and add a regression test asserting toJSON() is idempotent and leaves toHex() unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ripple-binary-codec): add Amount.toJSON idempotency tests for IOU and MPT, update changelog Extends the regression suite for XRPLF#3319 with idempotency checks on the IOU and MPT branches of Amount.toJSON() (both positive and negative values). These branches go through `new BinaryParser(this.toString())` and were not affected by the native-XRP buffer aliasing bug, but the tests guard against future regressions if either branch is rewritten to read from `this.bytes` directly. Also records the fix in HISTORY.md under the Unreleased section. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ripple-binary-codec): rename Amount.toJSON idempotency test variables for clarity Renames `hexBefore`/`first`/`second` to `serializedHexBeforeJsonCalls`/ `firstJsonResult`/`secondJsonResult` across all five idempotency tests so the assertion intent (two consecutive toJSON() calls produce the same result, and the encoded bytes are unchanged) is obvious to a reader without tracing the variables. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* security: redact private key material in getAlgorithmFromKey errors When key validation failed, keyError() interpolated the full hex key into the thrown Error.message. For private keys this propagated the secret to application logs, error-tracking services, and HTTP responses that echo error messages. Replace the key with "[redacted]" when type === 'private'. Public keys are still rendered since they are not sensitive. Add a test asserting the private-key hex is absent from the error message and a regression test pinning the redaction contract. * test: use framework-agnostic assertions for redaction tests The Karma (Jasmine) browser runner doesn't support expect.assertions or Jest-style expect(fn).toThrow(regex) message matching. Replace both with try/catch + expect(thrown).toBeDefined() and .toContain / .not .toContain on the error message, which work identically in Jest and Jasmine. Fixes ripple-keypairs:test:browser failures. * security: redact prefix byte in private key error messages * test: cover redaction for non-standard private key lengths * test: avoid Jest-only it.each in dual-runner test file
* update definitions * update path in skill and browser tests
…d / fromSecret (XRPLF#3337) * fix(xrpl): infer signing algorithm from seed prefix in Wallet.fromSeed / fromSecret When opts.algorithm is omitted, Wallet.deriveWallet no longer forces ed25519; the call passes through to ripple-keypairs.deriveKeypair, which infers the algorithm from the seed prefix (sEd… → ed25519, otherwise secp256k1). Resolves the long-standing bug where ingesting a secp256k1 family seed without an explicit algorithm produced an ed25519 keypair for an unrelated account (DGE-6641). Wallet.generate still passes algorithm explicitly and continues to default to ed25519, matching the agreed exception. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(xrpl): clarify walletFromSecretNumbers algorithm default in JSDoc Replace the stale `DEFAULT_ALGORITHM` comparison with an accurate description of how other Wallet factories (`fromSeed`/`fromSecret`) now infer the algorithm from the seed prefix, and surface the secp256k1 Xaman-compat default on the `opts.algorithm` param itself so tooltip and generated-doc readers see it without the surrounding prose. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Update Changelog and Release-details for isomorphic@1.0.2 package Co-authored-by: Chenna Keshava B S <ckeshavabs@gmail.com>
* release 5.0.1: ripple-address-codec package.json and CHANGELOG updates * minor: Update the date of the expected release of ripple-address-codec package * minor: Explicitly set isomorphic package to use at least 1.0.2 version --------- Co-authored-by: Chenna Keshava B S <ckeshavabs@gmail.com>
* release-rbc-2.8.0: Updates to package.json file and Changelog * minor: Use latest dep versions in package.json; Update the date in the Changelog release history * minor: update package-lock file with the latest versions of deps --------- Co-authored-by: Chenna Keshava B S <ckeshavabs@gmail.com>
Bumps [ip-address](https://github.com/beaugunderson/ip-address) from 10.1.0 to 10.2.0. - [Commits](beaugunderson/ip-address@v10.1.0...v10.2.0) --- updated-dependencies: - dependency-name: ip-address dependency-version: 10.2.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.5 to 0.2.7. - [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md) - [Commits](raszi/node-tmp@v0.2.5...v0.2.7) --- updated-dependencies: - dependency-name: tmp dependency-version: 0.2.7 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.0 to 3.1.2. - [Release notes](https://github.com/fastify/fast-uri/releases) - [Commits](fastify/fast-uri@v3.1.0...v3.1.2) --- updated-dependencies: - dependency-name: fast-uri dependency-version: 3.1.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [axios](https://github.com/axios/axios) and [nx](https://github.com/nrwl/nx/tree/HEAD/packages/nx). These dependencies needed to be updated together. Updates `axios` from 1.15.0 to 1.16.0 - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](axios/axios@v1.15.0...v1.16.0) Updates `nx` from 22.6.5 to 22.7.5 - [Release notes](https://github.com/nrwl/nx/releases) - [Commits](https://github.com/nrwl/nx/commits/22.7.5/packages/nx) --- updated-dependencies: - dependency-name: axios dependency-version: 1.16.0 dependency-type: indirect - dependency-name: nx dependency-version: 22.7.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
bump version Co-authored-by: Raj Patel <rajp@ripple.com>
update version Co-authored-by: Raj Patel <rajp@ripple.com>
bump vesion Co-authored-by: Raj Patel <rajp@ripple.com>
…3345) * update definitions * update path in skill and browser tests * add ReferenceHolding to MPTokenIssuance * update HISTORY.md * fix valutInfoResponse * fix AccountRoot * update history * move to Unreleased section
* 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>
Patel-Raj11
commented
Jun 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 viaMPTokenIssuanceSet. 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 replaceMPTokenMetadata/TransferFeeafter the fact.Scope (by category):
MutableFlagsadded toMPTokenIssuanceCreate;MutableFlags,MPTokenMetadata, andTransferFeeadded toMPTokenIssuanceSet, introducing a "mutate mode" mutually exclusive with the existing lock/unlock mode.MutableFlags(DEFAULT, UInt32) added toMPTokenIssuance.tmfMPTCanEnable*× 6 +tmfMPTCanMutate{Metadata,TransferFee}), set-side (tmfMPTSet*× 6), and on-ledger (lsmfMPTCanEnable*× 6 +lsmfMPTCanMutate{Metadata,TransferFee}) bit vocabularies.MutableFlags = 0and out-of-mask rejection on both transactions; mutate-mode/Holderexclusion; mutate-mode/universal-Flagsexclusion; metadata length cap (1024 bytes); transfer-fee cap (50000); pre-emptive refusal oftmfMPTSetCanTransferpaired with non-zeroTransferFeein the same tx.convertTxMutableFlagsToNumberregistered alongside the existing tx-flags converter and invoked from bothvalidate()andClient.autofill().sfMutableFlags(UInt32, nth=53),MPTokenIssuanceMutableledger flag enum, and the three updated transaction/ledger formats inripple-binary-codec'sdefinitions.json.DynamicMPTadded to.ci-config/xrpld.cfgso integration tests run against an activated amendment.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
MutableFlagsvalue 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
Did you update HISTORY.md?
Test Plan
MutableFlagsfield on all three hosts, every validation rule listed in the Scope section (rejection ofMutableFlags = 0, out-of-mask bits,Holderin mutate mode, universal-Flagsin mutate mode, oversizedMPTokenMetadata, oversizedTransferFee, and thetmfMPTSetCanTransfer+ non-zeroTransferFeecombination), and binary round-trip ofsfMutableFlagsonMPTokenIssuanceCreate,MPTokenIssuanceSet, and theMPTokenIssuanceledger entry.CanTransferenable followed byTransferFeemutation and clearing, and the mutate-permission gating path (a mutatingMPTokenIssuanceSetagainst an issuance that did not declare the corresponding mutability returnstecNO_PERMISSION).Notes for reviewers
CanEnable<Cap>(e.g.,tmfMPTCanEnableCanLock,lsmfMPTCanEnableCanLock) rather than theCanMutate<Cap>names in the XLS README; thetmfMPTClear*half of the XLS §4.1 set/clear pairs is gone; and the remainingtmfMPTSet*flags are renumbered to0x01..0x20. Metadata and TransferFee retainCanMutateon both sides. This SDK matches the rippled final state.lsfMPTCan<Cap>is set on an issuance — at creation via thetfMPTCan<Cap>create flag, or post-creation viatmfMPTSet<Cap>onMPTokenIssuanceSet— there is no protocol mechanism to clear it. Callers composing a mutatingMPTokenIssuanceSetshould treat capability enabling as irreversible; downstream UIs may want to surface this affordance.TransferFeemutation requires a staged enable. Setting a non-zeroTransferFeeonMPTokenIssuanceSetrequireslsfMPTCanTransferto already be set on the issuance; pairingtmfMPTSetCanTransferand a non-zeroTransferFeein the same tx does not satisfy the gate (rippled returnstecNO_PERMISSION). The SDK rejects that combination at validation time to pre-empt obvious-rejection submissions.{@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 theMPTokenMetadata/TransferFeefields onMPTokenIssuanceSet(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.resolveMPTokenIssuance{Create,Set}MutableFlagshelpers duplicate the centralisedconvertTxMutableFlagsToNumberlogic. The centralised converter runs first fromvalidate()/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.