This guide outlines the breaking changes between v6.x.x and v7.0.0 and provides an upgrade path for applications using xrpl4j.
Version 7.0.0 introduces several breaking changes:
- Issue Model Refactor —
Issuehas been refactored from a concrete immutable into a polymorphic interface with three subtypes (XrpIssue,IouIssue,MptIssue) to support the Single Asset Vault amendment. - Transaction Signing API Refactor —
SignatureUtils.addSignatureToTransaction()andSignatureUtils.addMultiSignaturesToTransaction()have been removed. Transaction signing now uses Immutables-generatedwithTransactionSignature()andwithSigners()methods onTransaction, and validation has moved to@Checkmethods onSingleSignedTransactionandMultiSignedTransaction.
Issue was previously an @Value.Immutable with a builder() method, a currency() field, and an optional
issuer() field. It is now a plain interface with three concrete implementations: XrpIssue, IouIssue, and
MptIssue. The Issue interface provides handle() and map() methods for type-safe polymorphic dispatch across the
three subtypes.
Issue.builder() and ImmutableIssue.Builder no longer exist. Use the concrete subtype builders instead.
Migration:
// Before (v6.x.x): XRP Issue
Issue xrp = Issue.builder().currency("XRP").build();
// After (v7.0.0): XRP Issue
Issue xrp = Issue.XRP; // or XrpIssue.XRP
// Before (v6.x.x): IOU Issue
Issue usd = Issue.builder()
.currency("USD")
.issuer(issuerAddress)
.build();
// After (v7.0.0): IOU Issue
Issue usd = IouIssue.builder()
.currency("USD")
.issuer(issuerAddress)
.build();You can now also create MPT issues:
// New in v7.0.0: MPT Issue
Issue mpt = MptIssue.builder()
.mptIssuanceId(mptIssuanceId)
.build();The currency() and issuer() accessors are no longer on the Issue interface. They have moved to the concrete
subtypes where they apply:
XrpIssue.currency()— always returns"XRP"IouIssue.currency()— returns the currency codeIouIssue.issuer()— returns the issuerAddressMptIssue.mptIssuanceId()— returns theMpTokenIssuanceId
Migration:
Use the handle() or map() methods to work with Issue instances polymorphically. For example, in v6.x.x you could
access currency and issuer directly from an AmmObject:
// Before (v6.x.x)
Issue issue = ammObject.asset();
String currency = issue.currency();
Optional<Address> issuer = issue.issuer();In v7.0.0, objects like VaultObject can hold any asset type (XRP, IOU, or MPT). Use handle() to dispatch based on
the concrete type:
// After (v7.0.0)
Issue issue = vaultObject.asset();
issue.handle(
// Handle XRP
xrpIssue -> {
String currency = xrpIssue.currency(); // "XRP"
},
// Handle IOU
iouIssue -> {
String currency = iouIssue.currency();
Address issuer = iouIssue.issuer();
},
// Handle MPT
mptIssue -> {
MpTokenIssuanceId issuanceId = mptIssue.mptIssuanceId();
}
);Or use map() to transform an Issue into a value:
Issue issue = vaultObject.asset();
String description = issue.map(
xrpIssue -> "XRP",
iouIssue -> iouIssue.currency() + "/" + iouIssue.issuer(),
mptIssue -> "MPT:" + mptIssue.mptIssuanceId()
);JSON serialization and deserialization remain compatible. The IssueDeserializer automatically selects the correct
subtype based on the JSON structure:
{"currency": "XRP"}→XrpIssue{"currency": "USD", "issuer": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn"}→IouIssue{"mpt_issuance_id": "00000001A407AF5856CFF3379945D823561023E8E5CED9C9"}→MptIssue
The transaction signing internals have been refactored to eliminate per-transaction-type switch statements in
SignatureUtils. This change leverages Immutables-generated builder methods on the Transaction interface.
This method contained a large switch statement with explicit handling for every transaction type. It has been removed.
The signing flow now uses Transaction.withTransactionSignature() directly.
Migration:
If you were calling addSignatureToTransaction() directly (uncommon — this was primarily used internally by
AbstractTransactionSigner):
// Before (v6.x.x)
SingleSignedTransaction<Payment> signed = signatureUtils.addSignatureToTransaction(payment, signature);
// After (v7.0.0)
Transaction signedTx = payment.withTransactionSignature(signature);
SingleSignedTransaction<Payment> signed = SingleSignedTransaction.<Payment>builder()
.unsignedTransaction(payment)
.signature(signature)
.signedTransaction((Payment) signedTx)
.build();This method has also been removed. Use Transaction.withSigners() instead.
Migration:
// Before (v6.x.x)
Transaction multiSigned = signatureUtils.addMultiSignaturesToTransaction(transaction, signerWrappers);
// After (v7.0.0)
Transaction multiSigned = transaction.withSigners(signerWrappers);Two new methods have been added to the Transaction interface. Immutables generates concrete implementations of these
for every transaction subclass:
Transaction withTransactionSignature(Signature signature)— returns a copy of the transaction with the signature applied.Transaction withSigners(Iterable<? extends SignerWrapper> signers)— returns a copy of the transaction with the specified signers applied.
- JSON serialization and deserialization remain compatible with the same JSON structure.
- The
Issue.XRPconstant is still available and works the same way. - The
TransactionSigner.sign()andTransactionSigner.multiSign()APIs are unchanged — only the internal implementation has changed. If you use these high-level APIs (e.g., viaBcSignatureService), no migration is needed for signing.
- XLS-0065 Specification: https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0065-single-asset-vault