MPT operations and metadata
Use the core xrpl/transaction and xrpl/transaction/types packages for MPT transactions. Start with Transactions for the common submission flow. Most examples are fragments: supply the account addresses, issuance ID, and client for your application.
Dynamic MPT
Use ImmutableFlags to make issuance capabilities or fields permanently immutable. Capability enablement on MPTokenIssuanceSet uses the normal transaction Flags field.
Create an issuance
MaximumAmount is a quoted base-10 types.MPTAmount from 1 through 2^63-1.
maximumAmount := types.MPTAmount(1000000)
immutableFlags := types.ImmutableFlags(
transaction.TifMPTCanLock |
transaction.TifMPTMetadata,
)
create := transaction.MPTokenIssuanceCreate{
BaseTx: transaction.BaseTx{
Account: types.Address(issuer),
TransactionType: transaction.MPTokenIssuanceCreateTx,
},
MaximumAmount: &maximumAmount,
ImmutableFlags: immutableFlags,
}
create.SetMPTCanLockFlag()
TfMPTCanHoldConfidentialBalance enables confidential balances. A non-zero transfer fee cannot be combined with that capability. See the confidential guide for the XLS-96 workflow this capability unlocks.
Update an issuance
Use TfMPTSet* flags or the matching setters to enable a capability. Use ImmutableFlags only to prevent later changes.
set := transaction.MPTokenIssuanceSet{
BaseTx: transaction.BaseTx{
Account: types.Address(issuer),
TransactionType: transaction.MPTokenIssuanceSetTx,
},
MPTokenIssuanceID: issuanceID,
}
set.SetMPTRequireAuthFlag()
set.SetMPTRequireAuthImmutableFlag()
Lock and unlock operations use TfMPTLock and TfMPTUnlock. A Holder-only transaction is a no-op and fails validation. Pair Holder with one of these flags. Lock and unlock operations cannot include capability, metadata, transfer-fee, or immutability mutations.
IssuerEncryptionKey and AuditorEncryptionKey register the ElGamal public keys XLS-96 confidential transfers need. Both are 33-byte compressed secp256k1 points, hex-encoded. MPTokenIssuanceCreate does not carry them, so an issuance enables the capability at creation and registers the keys with a later MPTokenIssuanceSet.
issuerKey := issuerKeypair.PubKeyHex
set := transaction.MPTokenIssuanceSet{
BaseTx: transaction.BaseTx{
Account: types.Address(issuer),
TransactionType: transaction.MPTokenIssuanceSetTx,
},
MPTokenIssuanceID: issuanceID,
IssuerEncryptionKey: &issuerKey,
}
AuditorEncryptionKey requires IssuerEncryptionKey in the same transaction, and neither can be combined with Holder.
Claw back MPT balances
Clawback accepts an MPT amount and requires the target Holder. The transaction Account must match the issuer encoded in the MPT issuance ID.
clawback := transaction.Clawback{
BaseTx: transaction.BaseTx{
Account: types.Address(issuer),
TransactionType: transaction.ClawbackTx,
},
Amount: types.MPTCurrencyAmount{
MPTIssuanceID: issuanceID,
Value: "25",
},
Holder: types.Address(holder),
}
The Holder must be omitted for an issued-currency clawback. Tagged holder X-addresses are rejected.
Ledger values
MPT ledger amount fields use quoted base-10 strings. This includes MPToken.MPTAmount, MPToken.LockedAmount, and the MaximumAmount, OutstandingAmount, and LockedAmount fields on MPTokenIssuance. OwnerNode fields are hexadecimal strings.
MPTokenIssuance.ImmutableFlags contains permanent restrictions and uses the LsifMPT* constants.
if issuance.ImmutableFlags&ledger.LsifMPTMetadata != 0 {
// Metadata can no longer change.
}
Encode, validate, and decode metadata
Use types.ParsedMPTokenMetadata to construct metadata. The required fields are Ticker, Name, Icon, AssetClass, and IssuerName. Encoding serializes it to hex. Encoding is not validation: call ValidateMPTokenMetadata to check the schema before attaching it to a transaction.
This offline round-trip uses real encoded output, not a truncated placeholder:
package main
import (
"fmt"
"log"
"github.com/Peersyst/xrpl-go/xrpl/transaction"
"github.com/Peersyst/xrpl-go/xrpl/transaction/types"
)
func main() {
subclass := "treasury"
metadata := types.ParsedMPTokenMetadata{
Ticker: "TBILL",
Name: "Example Treasury Token",
Icon: "https://example.org/token.png",
AssetClass: "rwa",
AssetSubclass: &subclass,
IssuerName: "Example Issuer",
}
encoded, err := types.EncodeMPTokenMetadata(metadata)
if err != nil {
log.Fatal(err)
}
if err := types.ValidateMPTokenMetadata(encoded); err != nil {
log.Fatal(err)
}
decoded, err := types.DecodeMPTokenMetadata(encoded)
if err != nil {
log.Fatal(err)
}
create := transaction.MPTokenIssuanceCreate{
BaseTx: transaction.BaseTx{
Account: "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
},
MPTokenMetadata: types.MPTokenMetadata(encoded),
}
fmt.Println("Ticker:", decoded.Ticker)
fmt.Println("Transaction type:", create.TxType())
}
This constructs a transaction but does not sign or submit it. Continue with the normal transaction flow.
Decoding accepts both long-form and compact-form JSON keys. Encoding uses compact keys with stable ordering. ValidateMPTokenMetadata checks hex/JSON syntax, the 1024-byte limit, required fields, allowed keys and values, and field-count limits. It returns MPTokenMetadataValidationErrors containing the validation failures.
See the Go metadata types for fields and the XLS-89 schema for requirements and enum values. In particular, AssetClass: "rwa" requires an asset subclass.
Protocol reference
Use the XRPL references for MPTokenIssuanceCreate, MPTokenIssuanceSet, and Clawback. SDK support does not establish amendment activation on your network.