Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
474eb81
added account permission delegation
cybele-ripple Feb 2, 2026
ba48f46
remove extra files
cybele-ripple Feb 5, 2026
7304367
defined explicit permission values, added unit tests, added lookups
cybele-ripple Feb 6, 2026
fc834c7
Merge branch 'main' into account-permission-delegation
cybele-ripple Feb 6, 2026
a9d902b
updated integration tests and field implementation
cybele-ripple Feb 6, 2026
bfc033d
Add ability to access flags from Transaction.java (#690)
sappenin Feb 7, 2026
ab0045c
Batch PR1: Add tfInnerBatchTxn to all transactions
sappenin Feb 10, 2026
be9d4f7
added account permission delegation
cybele-ripple Feb 2, 2026
d9ff2f1
new enum for granularpermission, added transactiontype enum, check fo…
cybele-ripple Feb 18, 2026
9868950
removed incomplete file
cybele-ripple Feb 18, 2026
408efff
resolve merge conflicts
cybele-ripple Feb 18, 2026
af2fc8f
added integration tests related to Delegate
cybele-ripple Feb 19, 2026
d5ce28f
Merge branch 'main' into account-permission-delegation
sappenin Feb 20, 2026
be26ff3
combined delegateset and delegate it, updated GranularPermission to a…
cybele-ripple Feb 20, 2026
a270901
added metadelegateobject, updated metaledger, updated tests to reflec…
cybele-ripple Feb 20, 2026
4844bc4
removed changes made to UInt32Type and removed unit test that related…
cybele-ripple Feb 20, 2026
38c887c
added DelegateLedgerEntryParams and related tests, fixed line length …
cybele-ripple Feb 20, 2026
26c6a98
added for loop to create permissionValues from GranularPermission
cybele-ripple Feb 20, 2026
f3ca876
changed from null to return optional
cybele-ripple Feb 20, 2026
bd1b597
ensure line <=120 chars
cybele-ripple Feb 20, 2026
ea3dcea
remove extra blank lines, added test coverage for DefaultDefinitionsP…
cybele-ripple Feb 20, 2026
e32e21d
checkstyle fix
cybele-ripple Feb 20, 2026
30cf686
set version to 6.1.0-rc.1-SNAPSHOT
Patel-Raj11 Feb 21, 2026
35c6694
Set version back to HEAD-SNAPSHOT
sappenin Feb 21, 2026
198668f
renamed permissions to accountpermissions, streamlined listing granul…
cybele-ripple Feb 26, 2026
9f3b13a
Merge branch 'main' into account-permission-delegation
cybele-ripple Feb 26, 2026
bfdaafc
added test coverage
cybele-ripple Feb 26, 2026
5bd0628
fixed snapshot typo
cybele-ripple Feb 26, 2026
2b357cc
added coverage for SignatureUtils.java
cybele-ripple Feb 26, 2026
7cc6652
used TransactionType for non_delegable_transactions
cybele-ripple Feb 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.io.Resources;
import org.xrpl.xrpl4j.model.transactions.GranularPermission;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class DefaultDefinitionsProvider implements DefinitionsProvider {
Expand All @@ -43,14 +46,52 @@ public DefaultDefinitionsProvider(final ObjectMapper objectMapper) {

this.supplier = Suppliers.memoize(() -> {
try {
return objectMapper.readerFor(Definitions.class)
Definitions baseDefinitions = objectMapper.readerFor(Definitions.class)
.readValue(Resources.getResource(DefaultDefinitionsProvider.class, "/definitions.json"));

// Generate PERMISSION_VALUES dynamically from TRANSACTION_TYPES
Map<String, Integer> permissionValues = generatePermissionValues(baseDefinitions);

// Return a new Definitions object with the generated PERMISSION_VALUES
return ImmutableDefinitions.builder()
.from(baseDefinitions)
.permissionValues(permissionValues)
.build();
} catch (IOException e) {
throw new IllegalStateException("Cannot read definition.json file", e);
}
});
}

/**
* Generate PERMISSION_VALUES mapping from TRANSACTION_TYPES.
* This follows the same logic as xrpl.js:
* - Granular permissions start at 65537
* - Transaction type permissions are transaction type code + 1
*
* @param definitions The base {@link Definitions} loaded from definitions.json
* @return A {@link Map} of permission names to their numeric values
*/
private Map<String, Integer> generatePermissionValues(Definitions definitions) {
Map<String, Integer> permissionValues = new HashMap<>();

// Add granular permissions from GranularPermission enum
for (GranularPermission permission : GranularPermission.values()) {
permissionValues.put(permission.value(), permission.numericValue());
}

// Add transaction type permissions (transaction type code + 1)
// Exclude Invalid (-1) only
definitions.transactionTypes().forEach((txType, txCode) -> {
// Skip Invalid (-1)
if (txCode >= 0) {
permissionValues.put(txType, txCode + 1);
}
});

return permissionValues;
}

@Override
public Definitions get() {
return supplier.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.collect.ImmutableMap;
import org.immutables.value.Value.Default;
import org.immutables.value.Value.Immutable;

import java.util.List;
Expand Down Expand Up @@ -77,4 +79,16 @@ public interface Definitions {
@JsonProperty("TRANSACTION_RESULTS")
Map<String, Integer> transactionResults();

/**
* Permission values mappings (permission value to ordinal value).
* This field is not present in the generated definitions.json file and is populated
* programmatically by {@link DefaultDefinitionsProvider}.
*
* @return {@link Map} keyed by {@link String} with {@link Integer} values for all permission values.
*/
@JsonProperty("PERMISSION_VALUES")
@Default
default Map<String, Integer> permissionValues() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Immutables should fill-in default collections for you automagically, so I think this can be updated to this instead (unless you have some reason to keep this as-is):

 @JsonProperty("PERMISSION_VALUES")
 Map<String, Integer> permissionValues();

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added

return ImmutableMap.of();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public class DefinitionsService {

private final Map<Integer, String> ledgerEntryTypeReverseLookupMap;

private final Map<Integer, String> permissionValueReverseLookupMap;

/**
* Required-args Constructor.
*
Expand Down Expand Up @@ -84,6 +86,7 @@ public class DefinitionsService {
this.transactionTypeReverseLookupMap = inverse(definitions.transactionTypes());
this.transactionResultReverseLookupNap = inverse(definitions.transactionResults());
this.ledgerEntryTypeReverseLookupMap = inverse(definitions.ledgerEntryTypes());
this.permissionValueReverseLookupMap = inverse(definitions.permissionValues());
}

/**
Expand Down Expand Up @@ -184,6 +187,8 @@ public Optional<Integer> mapFieldSpecialization(String fieldName, String value)
return Optional.ofNullable(definitions.transactionResults().get(value));
case "TransactionType":
return Optional.ofNullable(definitions.transactionTypes().get(value));
case "PermissionValue":
return Optional.ofNullable(definitions.permissionValues().get(value));
default:
return Optional.empty();
}
Expand All @@ -208,6 +213,8 @@ public Optional<String> mapFieldRawValueToSpecialization(String fieldName, Strin
return Optional.ofNullable(transactionResultReverseLookupNap.get(Integer.valueOf(value)));
case "TransactionType":
return Optional.ofNullable(transactionTypeReverseLookupMap.get(Integer.valueOf(value)));
case "PermissionValue":
return Optional.ofNullable(permissionValueReverseLookupMap.get(Integer.valueOf(value)));
default:
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.xrpl.xrpl4j.model.transactions.CredentialAccept;
import org.xrpl.xrpl4j.model.transactions.CredentialCreate;
import org.xrpl.xrpl4j.model.transactions.CredentialDelete;
import org.xrpl.xrpl4j.model.transactions.DelegateSet;
import org.xrpl.xrpl4j.model.transactions.DepositPreAuth;
import org.xrpl.xrpl4j.model.transactions.DidDelete;
import org.xrpl.xrpl4j.model.transactions.DidSet;
Expand Down Expand Up @@ -481,6 +482,10 @@ public <T extends Transaction> SingleSignedTransaction<T> addSignatureToTransact
transactionWithSignature = CredentialDelete.builder().from((CredentialDelete) transaction)
.transactionSignature(signature)
.build();
} else if (DelegateSet.class.isAssignableFrom(transaction.getClass())) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: Since we are adding tests in SignatureUtilsTest for all transaction types, we should add it for DelegateSet.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I see this comment as resolved, but when I run SignatureUtilsTest.java with coverage, it shows this as still uncovered.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added coverage for this line and reran tests with coverage to confirm

transactionWithSignature = DelegateSet.builder().from((DelegateSet) transaction)
.transactionSignature(signature)
.build();
} else if (PermissionedDomainSet.class.isAssignableFrom(transaction.getClass())) {
transactionWithSignature = PermissionedDomainSet.builder().from((PermissionedDomainSet) transaction)
.transactionSignature(signature)
Expand Down Expand Up @@ -736,6 +741,10 @@ public <T extends Transaction> T addMultiSignaturesToTransaction(T transaction,
transactionWithSignatures = CredentialDelete.builder().from((CredentialDelete) transaction)
.signers(signers)
.build();
} else if (DelegateSet.class.isAssignableFrom(transaction.getClass())) {
transactionWithSignatures = DelegateSet.builder().from((DelegateSet) transaction)
.signers(signers)
.build();
} else if (PermissionedDomainSet.class.isAssignableFrom(transaction.getClass())) {
transactionWithSignatures = PermissionedDomainSet.builder().from((PermissionedDomainSet) transaction)
.signers(signers)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.xrpl.xrpl4j.model.client.ledger;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.annotations.Beta;
import org.immutables.value.Value.Immutable;
import org.xrpl.xrpl4j.model.transactions.Address;

/**
* Parameters that uniquely identify a {@link org.xrpl.xrpl4j.model.ledger.DelegateObject} on ledger that can be
* used in a {@link LedgerEntryRequestParams} to request a {@link org.xrpl.xrpl4j.model.ledger.DelegateObject}.
*
* <p>This class will be marked {@link Beta} until the featurePermissionDelegation amendment is enabled on mainnet.
* Its API is subject to change.</p>
*/
@Immutable
@JsonSerialize(as = ImmutableDelegateLedgerEntryParams.class)
@JsonDeserialize(as = ImmutableDelegateLedgerEntryParams.class)
@Beta
public interface DelegateLedgerEntryParams {

/**
* Construct a {@code DelegateLedgerEntryParams} builder.
*
* @return An {@link ImmutableDelegateLedgerEntryParams.Builder}.
*/
static ImmutableDelegateLedgerEntryParams.Builder builder() {
return ImmutableDelegateLedgerEntryParams.builder();
}

/**
* The account that wants to authorize another account (the delegating account).
*
* @return An {@link Address}.
*/
Address account();

/**
* The authorized account (the delegate).
*
* @return An {@link Address}.
*/
Address authorize();
}

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.xrpl.xrpl4j.model.ledger.BridgeObject;
import org.xrpl.xrpl4j.model.ledger.CheckObject;
import org.xrpl.xrpl4j.model.ledger.CredentialObject;
import org.xrpl.xrpl4j.model.ledger.DelegateObject;
import org.xrpl.xrpl4j.model.ledger.DepositPreAuthObject;
import org.xrpl.xrpl4j.model.ledger.DidObject;
import org.xrpl.xrpl4j.model.ledger.EscrowObject;
Expand Down Expand Up @@ -445,6 +446,25 @@ static LedgerEntryRequestParams<PermissionedDomainObject> permissionedDomain(
.build();
}

/**
* Construct a {@link LedgerEntryRequestParams} that requests a {@link DelegateObject} ledger entry.
*
* @param params The {@link DelegateLedgerEntryParams} that uniquely identify the
* {@link DelegateObject} on ledger.
* @param ledgerSpecifier A {@link LedgerSpecifier} indicating the ledger to query data from.
*
* @return A {@link LedgerEntryRequestParams} for {@link DelegateObject}.
*/
static LedgerEntryRequestParams<DelegateObject> delegate(
DelegateLedgerEntryParams params,
LedgerSpecifier ledgerSpecifier
) {
return ImmutableLedgerEntryRequestParams.<DelegateObject>builder()
.delegate(params)
.ledgerSpecifier(ledgerSpecifier)
.build();
}

/**
* Specifies the ledger version to request. A ledger version can be specified by ledger hash, numerical ledger index,
* or a shortcut value.
Expand Down Expand Up @@ -610,6 +630,13 @@ default boolean binary() {
@JsonProperty("permissioned_domain")
Optional<PermissionedDomainLedgerEntryParams> permissionedDomain();

/**
* Look up a {@link org.xrpl.xrpl4j.model.ledger.DelegateObject} by {@link DelegateLedgerEntryParams}.
*
* @return An optionally-present {@link DelegateLedgerEntryParams}.
*/
Optional<DelegateLedgerEntryParams> delegate();

/**
* The {@link Class} of {@link T}. This field is helpful when telling Jackson how to deserialize rippled's response to
* a {@link T}.
Expand Down Expand Up @@ -687,6 +714,10 @@ default Class<T> ledgerObjectClass() {
return (Class<T>) PermissionedDomainObject.class;
}

if (delegate().isPresent()) {
return (Class<T>) DelegateObject.class;
}

return (Class<T>) LedgerObject.class;
}
}
Loading
Loading