This interface will be marked {@link Beta} until the featureXChainBridge amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableXChainCreateBridge.class)
+@JsonDeserialize(as = ImmutableXChainCreateBridge.class)
+public interface XChainCreateBridge extends Transaction {
+
+ /**
+ * Construct a {@code XChainCreateBridge} builder.
+ *
+ * @return An {@link ImmutableXChainCreateBridge.Builder}.
+ */
+ static ImmutableXChainCreateBridge.Builder builder() {
+ return ImmutableXChainCreateBridge.builder();
+ }
+
+ /**
+ * Set of {@link TransactionFlags}s for this {@link XChainCreateBridge}, which only allows the
+ * {@code tfFullyCanonicalSig} flag, which is deprecated.
+ *
+ * @return A set of {@link TransactionFlags}, default is {@link TransactionFlags#EMPTY}.
+ */
+ @JsonProperty("Flags")
+ @Value.Default
+ default TransactionFlags flags() {
+ return TransactionFlags.EMPTY;
+ }
+
+ /**
+ * The minimum amount, in XRP, required for a {@link XChainAccountCreateCommit} transaction. If this isn't present,
+ * the {@link XChainAccountCreateCommit} transaction will fail. This field can only be present on XRP-XRP bridges.
+ *
+ * @return An optionally-present {@link XrpCurrencyAmount}.
+ */
+ @JsonProperty("MinAccountCreateAmount")
+ Optional minAccountCreateAmount();
+
+ /**
+ * The total amount to pay the witness servers for their signatures. This amount will be split among the signers.
+ *
+ * @return An {@link XrpCurrencyAmount}.
+ */
+ @JsonProperty("SignatureReward")
+ XrpCurrencyAmount signatureReward();
+
+ /**
+ * The bridge (door accounts and assets) to create.
+ *
+ * @return An {@link XChainBridge}.
+ */
+ @JsonProperty("XChainBridge")
+ @SuppressWarnings("MethodName")
+ XChainBridge xChainBridge();
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/XChainCreateClaimId.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/XChainCreateClaimId.java
new file mode 100644
index 000000000..1e4525b36
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/XChainCreateClaimId.java
@@ -0,0 +1,70 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+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;
+import org.immutables.value.Value.Immutable;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+
+/**
+ * Object mapping for the {@code XChainCreateClaimId} transaction.
+ *
+ * This interface will be marked {@link Beta} until the featureXChainBridge amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableXChainCreateClaimId.class)
+@JsonDeserialize(as = ImmutableXChainCreateClaimId.class)
+public interface XChainCreateClaimId extends Transaction {
+
+ /**
+ * Construct a {@code XChainCreateClaimId} builder.
+ *
+ * @return An {@link ImmutableXChainCreateClaimId.Builder}.
+ */
+ static ImmutableXChainCreateClaimId.Builder builder() {
+ return ImmutableXChainCreateClaimId.builder();
+ }
+
+ /**
+ * Set of {@link TransactionFlags}s for this {@link XChainCreateClaimId}, which only allows the
+ * {@code tfFullyCanonicalSig} flag, which is deprecated.
+ *
+ * @return A set of {@link TransactionFlags}, default is {@link TransactionFlags#EMPTY}.
+ */
+ @JsonProperty("Flags")
+ @Value.Default
+ default TransactionFlags flags() {
+ return TransactionFlags.EMPTY;
+ }
+
+ /**
+ * The account that must send the {@link XChainCommit} transaction on the source chain.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("OtherChainSource")
+ Address otherChainSource();
+
+ /**
+ * The amount, in XRP, to reward the witness servers for providing signatures. This must match the amount on the
+ * {@code Bridge} ledger object.
+ *
+ * @return An {@link XrpCurrencyAmount}.
+ */
+ @JsonProperty("SignatureReward")
+ XrpCurrencyAmount signatureReward();
+
+ /**
+ * The bridge to create the claim ID for.
+ *
+ * @return An {@link XChainBridge}.
+ */
+ @JsonProperty("XChainBridge")
+ @SuppressWarnings("MethodName")
+ XChainBridge xChainBridge();
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/XChainModifyBridge.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/XChainModifyBridge.java
new file mode 100644
index 000000000..8df520a1f
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/XChainModifyBridge.java
@@ -0,0 +1,76 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+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;
+import org.immutables.value.Value.Immutable;
+import org.xrpl.xrpl4j.model.flags.PaymentFlags;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+import org.xrpl.xrpl4j.model.flags.XChainModifyBridgeFlags;
+
+import java.util.Optional;
+
+/**
+ * Object mapping for the {@code XChainModifyBridge} transaction.
+ *
+ * This interface will be marked {@link Beta} until the featureXChainBridge amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableXChainModifyBridge.class)
+@JsonDeserialize(as = ImmutableXChainModifyBridge.class)
+public interface XChainModifyBridge extends Transaction {
+
+ /**
+ * Construct a {@code XChainModifyBridge} builder.
+ *
+ * @return An {@link ImmutableXChainModifyBridge.Builder}.
+ */
+ static ImmutableXChainModifyBridge.Builder builder() {
+ return ImmutableXChainModifyBridge.builder();
+ }
+
+ /**
+ * Set of {@link XChainModifyBridgeFlags}s for this {@link XChainModifyBridge}, which have been properly combined to
+ * yield a {@link XChainModifyBridgeFlags} object containing the {@link Long} representation of the set bits.
+ *
+ * The value of the flags can either be set manually, or constructed using {@link XChainModifyBridgeFlags.Builder}.
+ *
+ * @return The {@link XChainModifyBridgeFlags} for this transaction.
+ */
+ @JsonProperty("Flags")
+ @Value.Default
+ default XChainModifyBridgeFlags flags() {
+ return XChainModifyBridgeFlags.empty();
+ }
+
+ /**
+ * The minimum amount, in XRP, required for a {@link XChainAccountCreateCommit} transaction. If this isn't present,
+ * the {@link XChainAccountCreateCommit} transaction will fail. This field can only be present on XRP-XRP bridges.
+ *
+ * @return An optionally-present {@link XrpCurrencyAmount}.
+ */
+ @JsonProperty("MinAccountCreateAmount")
+ Optional minAccountCreateAmount();
+
+ /**
+ * The signature reward split between the witnesses for submitting attestations.
+ *
+ * @return An optionally-present {@link XrpCurrencyAmount}.
+ */
+ @JsonProperty("SignatureReward")
+ Optional signatureReward();
+
+ /**
+ * The bridge to create the claim ID for.
+ *
+ * @return An {@link XChainBridge}.
+ */
+ @JsonProperty("XChainBridge")
+ @SuppressWarnings("MethodName")
+ XChainBridge xChainBridge();
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaBridgeObject.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaBridgeObject.java
new file mode 100644
index 000000000..dca99e082
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaBridgeObject.java
@@ -0,0 +1,145 @@
+package org.xrpl.xrpl4j.model.transactions.metadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.annotations.Beta;
+import com.google.common.primitives.UnsignedInteger;
+import org.immutables.value.Value;
+import org.immutables.value.Value.Immutable;
+import org.xrpl.xrpl4j.model.flags.Flags;
+import org.xrpl.xrpl4j.model.ledger.ImmutableBridgeObject;
+import org.xrpl.xrpl4j.model.ledger.LedgerObject;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.XChainAccountCreateCommit;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainClaimId;
+import org.xrpl.xrpl4j.model.transactions.XChainCount;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+import java.util.Optional;
+
+/**
+ * Represents a single cross-chain bridge that connects the XRP Ledger with another blockchain, such as its sidechain,
+ * and enables value in the form of XRP and other tokens (IOUs) to move efficiently between the two blockchains.
+ *
+ * This interface will be marked {@link Beta} until the featureXChainBridge amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableMetaBridgeObject.class)
+@JsonDeserialize(as = ImmutableMetaBridgeObject.class)
+public interface MetaBridgeObject extends MetaLedgerObject {
+
+ /**
+ * A bit-map of boolean flags. No flags are defined for {@link MetaBridgeObject}, so this value is always 0.
+ *
+ * @return Always {@link Flags#UNSET}.
+ */
+ @JsonProperty("Flags")
+ @Value.Derived
+ default Flags flags() {
+ return Flags.UNSET;
+ }
+
+ /**
+ * The account that owns this object.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("Account")
+ Optional account();
+
+ /**
+ * The minimum amount, in XRP, required for an XChainAccountCreateCommit transaction. If this isn't present, the
+ * {@link org.xrpl.xrpl4j.model.transactions.XChainAccountCreateCommit} transaction will fail. This field can only be
+ * present on XRP-XRP bridges.
+ *
+ * @return An optionally-present {@link XrpCurrencyAmount}.
+ */
+ @JsonProperty("MinAccountCreateAmount")
+ Optional minAccountCreateAmount();
+
+ /**
+ * The total amount, in XRP, to be rewarded for providing a signature for cross-chain transfer or for signing for the
+ * cross-chain reward. This amount will be split among the signers.
+ *
+ * @return An {@link XrpCurrencyAmount}.
+ */
+ @JsonProperty("SignatureReward")
+ Optional signatureReward();
+
+ /**
+ * The door accounts and assets of the bridge this object correlates to.
+ *
+ * @return An {@link XChainBridge}.
+ */
+ @JsonProperty("XChainBridge")
+ @SuppressWarnings("MethodName")
+ Optional xChainBridge();
+
+ /**
+ * The value of the next XChainClaimID to be created.
+ *
+ * @return An {@link XChainClaimId}.
+ */
+ @JsonProperty("XChainClaimID")
+ @SuppressWarnings("MethodName")
+ Optional xChainClaimId();
+
+ /**
+ * A counter used to order the execution of account create transactions. It is incremented every time a successful
+ * {@link org.xrpl.xrpl4j.model.transactions.XChainAccountCreateCommit} transaction is run for the source chain.
+ *
+ * @return An {@link XChainCount}.
+ */
+ @JsonProperty("XChainAccountCreateCount")
+ @SuppressWarnings("MethodName")
+ Optional xChainAccountCreateCount();
+
+ /**
+ * A counter used to order the execution of account create transactions. It is incremented every time a
+ * {@link org.xrpl.xrpl4j.model.transactions.XChainAccountCreateCommit} transaction is "claimed" on the destination
+ * chain. When the "claim" transaction is run on the destination chain, the {@link #xChainAccountClaimCount()} must
+ * match the value that the {@link #xChainAccountCreateCount()} had at the time the {@link #xChainAccountClaimCount()}
+ * was run on the source chain. This orders the claims so that they run in the same order that the
+ * {@link org.xrpl.xrpl4j.model.transactions.XChainAccountCreateCommit} transactions ran on the source chain, to
+ * prevent transaction replay.
+ *
+ * @return An {@link XChainCount}.
+ */
+ @JsonProperty("XChainAccountClaimCount")
+ @SuppressWarnings("MethodName")
+ Optional xChainAccountClaimCount();
+
+ /**
+ * A hint indicating which page of the sender's owner directory links to this object, in case the directory consists
+ * of multiple pages.
+ *
+ * Note: The object does not contain a direct link to the owner directory containing it, since that value can be
+ * derived from the Account.
+ *
+ * @return A {@link String} containing the owner node hint.
+ */
+ @JsonProperty("OwnerNode")
+ Optional ownerNode();
+
+ /**
+ * The identifying hash of the transaction that most recently modified this object.
+ *
+ * @return A {@link Hash256} containing the previous transaction hash.
+ */
+ @JsonProperty("PreviousTxnID")
+ Optional previousTransactionId();
+
+ /**
+ * The index of the ledger that contains the transaction that most recently modified this object.
+ *
+ * @return An {@link UnsignedInteger} representing the previous transaction ledger sequence.
+ */
+ @JsonProperty("PreviousTxnLgrSeq")
+ Optional previousTransactionLedgerSequence();
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryType.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryType.java
index f1f07f9fd..8c1a24936 100644
--- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryType.java
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryType.java
@@ -1,8 +1,11 @@
package org.xrpl.xrpl4j.model.transactions.metadata;
+import com.fasterxml.jackson.annotation.JsonIgnore;
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;
+import org.immutables.value.Value.Derived;
@Value.Immutable
@JsonSerialize(as = ImmutableMetaLedgerEntryType.class)
@@ -27,10 +30,22 @@ public interface MetaLedgerEntryType {
MetaLedgerEntryType NFTOKEN_PAGE = MetaLedgerEntryType.of("NFTokenPage");
MetaLedgerEntryType AMM = MetaLedgerEntryType.of("AMM");
+ @Beta
+ MetaLedgerEntryType BRIDGE = MetaLedgerEntryType.of("Bridge");
+
+ @Beta
+ MetaLedgerEntryType XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID = MetaLedgerEntryType.of(
+ "XChainOwnedCreateAccountClaimID"
+ );
+
+ @Beta
+ MetaLedgerEntryType XCHAIN_OWNED_CLAIM_ID = MetaLedgerEntryType.of("XChainOwnedClaimID");
+
/**
* Construct a new {@link MetaLedgerEntryType} from a {@link String}.
*
* @param value The {@link String} value.
+ *
* @return A {@link MetaLedgerEntryType} wrapping the supplied value.
*/
static MetaLedgerEntryType of(String value) {
@@ -39,6 +54,50 @@ static MetaLedgerEntryType of(String value) {
.build();
}
+ /**
+ * Get the {@link MetaLedgerObject} concrete type associated with this {@link MetaLedgerEntryType}.
+ *
+ * @return A {@link Class} of {@link MetaLedgerObject}.
+ */
+ @Derived
+ @JsonIgnore
+ default Class extends MetaLedgerObject> ledgerObjectType() {
+ switch (this.value()) {
+ case "AccountRoot":
+ return MetaAccountRootObject.class;
+ case "Check":
+ return MetaCheckObject.class;
+ case "DepositPreauth":
+ return MetaDepositPreAuthObject.class;
+ case "Escrow":
+ return MetaEscrowObject.class;
+ case "NFTokenOffer":
+ return MetaNfTokenOfferObject.class;
+ case "Offer":
+ return MetaOfferObject.class;
+ case "PayChannel":
+ return MetaPayChannelObject.class;
+ case "RippleState":
+ return MetaRippleStateObject.class;
+ case "SignerList":
+ return MetaSignerListObject.class;
+ case "Ticket":
+ return MetaTicketObject.class;
+ case "NFTokenPage":
+ return MetaNfTokenPageObject.class;
+ case "AMM":
+ return MetaAmmObject.class;
+ case "Bridge":
+ return MetaBridgeObject.class;
+ case "XChainOwnedClaimID":
+ return MetaXChainOwnedClaimIdObject.class;
+ case "XChainOwnedCreateAccountClaimID":
+ return MetaXChainOwnedCreateAccountClaimIdObject.class;
+ default:
+ return MetaUnknownObject.class;
+ }
+ }
+
String value();
}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainClaimAttestation.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainClaimAttestation.java
new file mode 100644
index 000000000..a2852d1bc
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainClaimAttestation.java
@@ -0,0 +1,31 @@
+package org.xrpl.xrpl4j.model.transactions.metadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+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.ledger.ImmutableXChainClaimAttestation;
+
+/**
+ * A wrapper around {@link MetaXChainClaimProofSig}s.
+ *
+ * This class will be marked {@link Beta} until the featureXChainBridge amendment is enabled on mainnet. Its API is
+ * subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableMetaXChainClaimAttestation.class)
+@JsonDeserialize(as = ImmutableMetaXChainClaimAttestation.class)
+public interface MetaXChainClaimAttestation {
+
+ /**
+ * An {@link MetaXChainClaimProofSig}.
+ *
+ * @return An {@link MetaXChainClaimProofSig}.
+ */
+ @JsonProperty("XChainClaimProofSig")
+ @SuppressWarnings("MethodName")
+ MetaXChainClaimProofSig xChainClaimProofSig();
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainClaimProofSig.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainClaimProofSig.java
new file mode 100644
index 000000000..28d6bf2c6
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainClaimProofSig.java
@@ -0,0 +1,79 @@
+package org.xrpl.xrpl4j.model.transactions.metadata;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonFormat.Shape;
+import com.fasterxml.jackson.annotation.JsonProperty;
+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.crypto.keys.PublicKey;
+import org.xrpl.xrpl4j.model.ledger.ImmutableXChainClaimProofSig;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.CurrencyAmount;
+import org.xrpl.xrpl4j.model.transactions.XChainCommit;
+
+import java.util.Optional;
+
+/**
+ * Represents an attestation for an {@link MetaXChainOwnedClaimIdObject}.
+ *
+ * This class will be marked {@link Beta} until the featureXChainBridge amendment is enabled on mainnet. Its API is
+ * subject to change.
+ */
+@Immutable
+@JsonSerialize(as = ImmutableMetaXChainClaimProofSig.class)
+@JsonDeserialize(as = ImmutableMetaXChainClaimProofSig.class)
+public interface MetaXChainClaimProofSig {
+
+ /**
+ * The account on the door account's signer list that is signing the transaction.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("AttestationSignerAccount")
+ Optional attestationSignerAccount();
+
+ /**
+ * The public key used to verify the signature.
+ *
+ * @return A {@link PublicKey}.
+ */
+ @JsonProperty("PublicKey")
+ Optional publicKey();
+
+ /**
+ * The amount to claim in the {@link org.xrpl.xrpl4j.model.transactions.XChainCommit} transaction on the destination
+ * chain.
+ *
+ * @return A {@link CurrencyAmount}.
+ */
+ @JsonProperty("Amount")
+ Optional amount();
+
+ /**
+ * The account that should receive this signer's share of the SignatureReward.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("AttestationRewardAccount")
+ Optional attestationRewardAccount();
+
+ /**
+ * A boolean representing the chain where the event occurred.
+ *
+ * @return {@code true} if the event occurred on the locking chain, otherwise {@code false}.
+ */
+ @JsonProperty("WasLockingChainSend")
+ @JsonFormat(shape = Shape.NUMBER)
+ Optional wasLockingChainSend();
+
+ /**
+ * The destination account for the funds on the destination chain.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("Destination")
+ Optional destination();
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainCreateAccountAttestation.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainCreateAccountAttestation.java
new file mode 100644
index 000000000..629a2877f
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainCreateAccountAttestation.java
@@ -0,0 +1,30 @@
+package org.xrpl.xrpl4j.model.transactions.metadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+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;
+
+/**
+ * A wrapper around {@link MetaXChainCreateAccountProofSig}s.
+ *
+ * This class will be marked {@link Beta} until the AMM amendment is enabled on mainnet. Its API is subject to
+ * change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableMetaXChainCreateAccountAttestation.class)
+@JsonDeserialize(as = ImmutableMetaXChainCreateAccountAttestation.class)
+public interface MetaXChainCreateAccountAttestation {
+
+ /**
+ * An {@link MetaXChainCreateAccountProofSig}.
+ *
+ * @return An {@link MetaXChainCreateAccountProofSig}.
+ */
+ @JsonProperty("XChainCreateAccountProofSig")
+ @SuppressWarnings("MethodName")
+ MetaXChainCreateAccountProofSig xChainCreateAccountProofSig();
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainCreateAccountProofSig.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainCreateAccountProofSig.java
new file mode 100644
index 000000000..1b3b09fd9
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainCreateAccountProofSig.java
@@ -0,0 +1,90 @@
+package org.xrpl.xrpl4j.model.transactions.metadata;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonFormat.Shape;
+import com.fasterxml.jackson.annotation.JsonProperty;
+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.crypto.keys.PublicKey;
+import org.xrpl.xrpl4j.model.ledger.ImmutableXChainCreateAccountProofSig;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.CurrencyAmount;
+import org.xrpl.xrpl4j.model.transactions.XChainAccountCreateCommit;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+import java.util.Optional;
+
+/**
+ * Represents an attestation for an {@link MetaXChainOwnedCreateAccountClaimIdObject}.
+ *
+ * This interface will be marked {@link Beta} until the featureXChainBridge amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableMetaXChainCreateAccountProofSig.class)
+@JsonDeserialize(as = ImmutableMetaXChainCreateAccountProofSig.class)
+public interface MetaXChainCreateAccountProofSig {
+
+ /**
+ * The amount committed by the {@link org.xrpl.xrpl4j.model.transactions.XChainAccountCreateCommit} transaction on the
+ * source chain.
+ *
+ * @return A {@link CurrencyAmount}.
+ */
+ @JsonProperty("Amount")
+ Optional amount();
+
+ /**
+ * The total amount, in XRP, to be rewarded for providing a signature for cross-chain transfer or for signing for the
+ * cross-chain reward. This amount will be split among the signers.
+ *
+ * @return An {@link XrpCurrencyAmount}.
+ */
+ @JsonProperty("SignatureReward")
+ Optional signatureReward();
+
+ /**
+ * The account that should receive this signer's share of the {@link #signatureReward()}.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("AttestationRewardAccount")
+ Optional attestationRewardAccount();
+
+ /**
+ * The account on the door account's signer list that is signing the transaction.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("AttestationSignerAccount")
+ Optional attestationSignerAccount();
+
+ /**
+ * The destination account for the funds on the destination chain.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("Destination")
+ Optional destination();
+
+ /**
+ * The public key used to verify the signature.
+ *
+ * @return A {@link PublicKey}.
+ */
+ @JsonProperty("PublicKey")
+ Optional publicKey();
+
+ /**
+ * A boolean representing the chain where the event occurred.
+ *
+ * @return {@code true} if the event occurred on the locking chain, otherwise {@code false}.
+ */
+ @JsonProperty("WasLockingChainSend")
+ @JsonFormat(shape = Shape.NUMBER)
+ Optional wasLockingChainSend();
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainOwnedClaimIdObject.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainOwnedClaimIdObject.java
new file mode 100644
index 000000000..53914e68b
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainOwnedClaimIdObject.java
@@ -0,0 +1,142 @@
+package org.xrpl.xrpl4j.model.transactions.metadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.annotations.Beta;
+import com.google.common.primitives.UnsignedInteger;
+import org.immutables.value.Value;
+import org.immutables.value.Value.Immutable;
+import org.xrpl.xrpl4j.model.flags.Flags;
+import org.xrpl.xrpl4j.model.ledger.ImmutableXChainOwnedClaimIdObject;
+import org.xrpl.xrpl4j.model.ledger.LedgerObject;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainClaimId;
+import org.xrpl.xrpl4j.model.transactions.XChainCommit;
+import org.xrpl.xrpl4j.model.transactions.XChainCreateClaimId;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * An {@code XChainOwnedClaimID} object represents one cross-chain transfer of value and includes information of the
+ * account on the source chain that locks or burns the funds on the source chain.
+ *
+ * The {@code XChainOwnedClaimID} object must be acquired on the destination chain before submitting a
+ * {@link XChainCommit} on the source chain. Its purpose is to prevent transaction replay attacks and is also used as a
+ * place to collect attestations from witness servers.
+ *
+ * An {@link XChainCreateClaimId} transaction is used to create a new {@code XChainOwnedClaimID}. The ledger object
+ * is destroyed when the funds are successfully claimed on the destination chain.
+ *
+ * This interface will be marked {@link Beta} until the featureXChainBridge amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableMetaXChainOwnedClaimIdObject.class)
+@JsonDeserialize(as = ImmutableMetaXChainOwnedClaimIdObject.class)
+public interface MetaXChainOwnedClaimIdObject extends MetaLedgerObject {
+
+ /**
+ * A bit-map of boolean flags. No flags are defined for {@link MetaXChainOwnedClaimIdObject}, so this value is always
+ * 0.
+ *
+ * @return Always {@link Flags#UNSET}.
+ */
+ @JsonProperty("Flags")
+ @Value.Derived
+ default Flags flags() {
+ return Flags.UNSET;
+ }
+
+ /**
+ * The account that owns this object.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("Account")
+ Optional account();
+
+ /**
+ * The door accounts and assets of the bridge this object correlates to.
+ *
+ * @return An {@link XChainBridge}.
+ */
+ @JsonProperty("XChainBridge")
+ @SuppressWarnings("MethodName")
+ Optional xChainBridge();
+
+ /**
+ * The unique sequence number for a cross-chain transfer.
+ *
+ * @return An {@link XChainClaimId}.
+ */
+ @JsonProperty("XChainClaimID")
+ @SuppressWarnings("MethodName")
+ Optional xChainClaimId();
+
+ /**
+ * The account that must send the corresponding {@link org.xrpl.xrpl4j.model.transactions.XChainCommit} on the source
+ * chain. The destination may be specified in the {@link org.xrpl.xrpl4j.model.transactions.XChainCommit} transaction,
+ * which means that if the OtherChainSource isn't specified, another account can try to specify a different
+ * destination and steal the funds. This also allows tracking only a single set of signatures, since we know which
+ * account will send the {@link org.xrpl.xrpl4j.model.transactions.XChainCommit} transaction.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("OtherChainSource")
+ Optional otherChainSource();
+
+ /**
+ * Attestations collected from the witness servers. This includes the parameters needed to recreate the message that
+ * was signed, including the amount, which chain (locking or issuing), optional destination, and reward account for
+ * that signature.
+ *
+ * @return A {@link List} of {@link MetaXChainClaimAttestation}s.
+ */
+ @JsonProperty("XChainClaimAttestations")
+ @SuppressWarnings("MethodName")
+ List xChainClaimAttestations();
+
+ /**
+ * The total amount to pay the witness servers for their signatures. It must be at least the value of SignatureReward
+ * in the Bridge ledger object.
+ *
+ * @return An {@link XrpCurrencyAmount}.
+ */
+ @JsonProperty("SignatureReward")
+ Optional signatureReward();
+
+ /**
+ * A hint indicating which page of the sender's owner directory links to this object, in case the directory consists
+ * of multiple pages.
+ *
+ * Note: The object does not contain a direct link to the owner directory containing it, since that value can be
+ * derived from the Account.
+ *
+ * @return A {@link String} containing the owner node hint.
+ */
+ @JsonProperty("OwnerNode")
+ Optional ownerNode();
+
+ /**
+ * The identifying hash of the transaction that most recently modified this object.
+ *
+ * @return A {@link Hash256} containing the previous transaction hash.
+ */
+ @JsonProperty("PreviousTxnID")
+ Optional previousTransactionId();
+
+ /**
+ * The index of the ledger that contains the transaction that most recently modified this object.
+ *
+ * @return An {@link UnsignedInteger} representing the previous transaction ledger sequence.
+ */
+ @JsonProperty("PreviousTxnLgrSeq")
+ Optional previousTransactionLedgerSequence();
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainOwnedCreateAccountClaimIdObject.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainOwnedCreateAccountClaimIdObject.java
new file mode 100644
index 000000000..fed7e17d2
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaXChainOwnedCreateAccountClaimIdObject.java
@@ -0,0 +1,117 @@
+package org.xrpl.xrpl4j.model.transactions.metadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.annotations.Beta;
+import com.google.common.primitives.UnsignedInteger;
+import org.immutables.value.Value;
+import org.immutables.value.Value.Immutable;
+import org.xrpl.xrpl4j.model.flags.Flags;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainCount;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * The {@code XChainOwnedCreateAccountClaimID} ledger object is used to collect attestations for creating an account via
+ * a cross-chain transfer.
+ *
+ * It is created when an XChainAddAccountCreateAttestation transaction adds a signature attesting to a
+ * XChainAccountCreateCommit transaction and the XChainAccountCreateCount is greater than or equal to the current
+ * XChainAccountClaimCount on the Bridge ledger object.
+ *
+ * The ledger object is destroyed when all the attestations have been received and the funds have transferred to the
+ * new account.
+ *
+ * This interface will be marked {@link Beta} until the featureXChainBridge amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableMetaXChainOwnedCreateAccountClaimIdObject.class)
+@JsonDeserialize(as = ImmutableMetaXChainOwnedCreateAccountClaimIdObject.class)
+public interface MetaXChainOwnedCreateAccountClaimIdObject extends MetaLedgerObject {
+
+ /**
+ * A bit-map of boolean flags. No flags are defined for {@link MetaXChainOwnedCreateAccountClaimIdObject}, so this
+ * value is always 0.
+ *
+ * @return Always {@link Flags#UNSET}.
+ */
+ @JsonProperty("Flags")
+ @Value.Derived
+ default Flags flags() {
+ return Flags.UNSET;
+ }
+
+ /**
+ * The account that owns this object.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("Account")
+ Optional account();
+
+ /**
+ * The door accounts and assets of the bridge this object correlates to.
+ *
+ * @return An {@link XChainBridge}.
+ */
+ @JsonProperty("XChainBridge")
+ @SuppressWarnings("MethodName")
+ Optional xChainBridge();
+
+ /**
+ * Attestations collected from the witness servers. This includes the parameters needed to recreate the message that
+ * was signed, including the amount, destination, signature reward amount, and reward account for that signature. With
+ * the exception of the reward account, all signatures must sign the message created with common parameters.
+ *
+ * @return A {@link List} of {@link MetaXChainCreateAccountAttestation}s.
+ */
+ @JsonProperty("XChainCreateAccountAttestations")
+ @SuppressWarnings("MethodName")
+ List xChainCreateAccountAttestations();
+
+ /**
+ * An integer that determines the order that accounts created through cross-chain transfers must be performed. Smaller
+ * numbers must execute before larger numbers.
+ *
+ * @return An {@link XChainCount}.
+ */
+ @JsonProperty("XChainAccountCreateCount")
+ @SuppressWarnings("MethodName")
+ Optional xChainAccountCreateCount();
+
+ /**
+ * A hint indicating which page of the sender's owner directory links to this object, in case the directory consists
+ * of multiple pages.
+ *
+ * Note: The object does not contain a direct link to the owner directory containing it, since that value can be
+ * derived from the Account.
+ *
+ * @return A {@link String} containing the owner node hint.
+ */
+ @JsonProperty("OwnerNode")
+ Optional ownerNode();
+
+ /**
+ * The identifying hash of the transaction that most recently modified this object.
+ *
+ * @return A {@link Hash256} containing the previous transaction hash.
+ */
+ @JsonProperty("PreviousTxnID")
+ Optional previousTransactionId();
+
+ /**
+ * The index of the ledger that contains the transaction that most recently modified this object.
+ *
+ * @return An {@link UnsignedInteger} representing the previous transaction ledger sequence.
+ */
+ @JsonProperty("PreviousTxnLgrSeq")
+ Optional previousTransactionLedgerSequence();
+
+}
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java
index 8520ac601..292c14e30 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,6 +22,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -34,6 +35,7 @@
import org.junit.jupiter.api.Test;
import org.xrpl.xrpl4j.codec.binary.XrplBinaryCodec;
import org.xrpl.xrpl4j.crypto.keys.PublicKey;
+import org.xrpl.xrpl4j.crypto.signing.Signature;
import org.xrpl.xrpl4j.model.flags.AccountSetTransactionFlags;
import org.xrpl.xrpl4j.model.flags.OfferCreateFlags;
import org.xrpl.xrpl4j.model.flags.PaymentChannelClaimFlags;
@@ -41,7 +43,9 @@
import org.xrpl.xrpl4j.model.flags.RippleStateFlags;
import org.xrpl.xrpl4j.model.flags.TransactionFlags;
import org.xrpl.xrpl4j.model.flags.TrustSetFlags;
+import org.xrpl.xrpl4j.model.flags.XChainModifyBridgeFlags;
import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory;
+import org.xrpl.xrpl4j.model.ledger.Issue;
import org.xrpl.xrpl4j.model.ledger.RippleStateObject;
import org.xrpl.xrpl4j.model.ledger.SignerEntry;
import org.xrpl.xrpl4j.model.ledger.SignerEntryWrapper;
@@ -57,6 +61,12 @@
import org.xrpl.xrpl4j.model.transactions.EscrowCreate;
import org.xrpl.xrpl4j.model.transactions.EscrowFinish;
import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainAccountCreateCommit;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainAddClaimAttestation;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainClaim;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainCreateBridge;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainCreateClaimId;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainModifyBridge;
import org.xrpl.xrpl4j.model.transactions.IssuedCurrencyAmount;
import org.xrpl.xrpl4j.model.transactions.NetworkId;
import org.xrpl.xrpl4j.model.transactions.OfferCancel;
@@ -69,6 +79,17 @@
import org.xrpl.xrpl4j.model.transactions.SignerListSet;
import org.xrpl.xrpl4j.model.transactions.Transaction;
import org.xrpl.xrpl4j.model.transactions.TrustSet;
+import org.xrpl.xrpl4j.model.transactions.XChainAccountCreateCommit;
+import org.xrpl.xrpl4j.model.transactions.XChainAddAccountCreateAttestation;
+import org.xrpl.xrpl4j.model.transactions.XChainAddClaimAttestation;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainClaim;
+import org.xrpl.xrpl4j.model.transactions.XChainClaimId;
+import org.xrpl.xrpl4j.model.transactions.XChainCommit;
+import org.xrpl.xrpl4j.model.transactions.XChainCount;
+import org.xrpl.xrpl4j.model.transactions.XChainCreateBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainCreateClaimId;
+import org.xrpl.xrpl4j.model.transactions.XChainModifyBridge;
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
import java.math.BigDecimal;
@@ -925,7 +946,6 @@ void serializeTrustSetWithEmptyFlags() throws JsonProcessingException {
.networkId(NetworkId.of(UnsignedInteger.MAX_VALUE))
.build();
-
String expectedBinary = "12001421FFFFFFFF240000002C63D6438D7EA4C68000000000000000000000000000574347000000" +
"0000832297BEF589D59F9C03A84F920F8D9128CC1CE468400000000000000C73008114BE6C30732AE33CF2AF3344CE8172A6B9" +
"300183E3";
@@ -946,7 +966,6 @@ void serializeTrustSetWithZeroFlags() throws JsonProcessingException {
.build())
.build();
-
String expectedBinary = "1200142200000000240000002C63D6438D7EA4C68000000000000000000000000000574347000000" +
"0000832297BEF589D59F9C03A84F920F8D9128CC1CE468400000000000000C73008114BE6C30732AE33CF2AF3344CE8172A6B9" +
"300183E3";
@@ -969,7 +988,6 @@ void serializeTrustSetWithNonZeroFlags() throws JsonProcessingException {
.build())
.build();
-
String expectedBinary = "1200142280020000240000002C63D6438D7EA4C68000000000000000000000000000574347000000" +
"0000832297BEF589D59F9C03A84F920F8D9128CC1CE468400000000000000C73008114BE6C30732AE33CF2AF3344CE8172A6B9" +
"300183E3";
@@ -1693,6 +1711,331 @@ void serializeSignerListSetWithNonZeroFlags() throws JsonProcessingException {
assertSerializesAndDeserializes(signerListSet, expectedBinary);
}
+ @Test
+ void serializeXChainAccountCreateCommitTest() throws JsonProcessingException {
+ XChainAccountCreateCommit commit = XChainAccountCreateCommit.builder()
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .amount(XrpCurrencyAmount.ofDrops(1000000))
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .destination(Address.of("rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL"))
+ .sequence(UnsignedInteger.ONE)
+ .signatureReward(XrpCurrencyAmount.ofDrops(10000))
+ .signingPublicKey(PublicKey.fromBase16EncodedPublicKey("0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB3265" +
+ "4A313222F7FD020"))
+ .transactionSignature(Signature.fromBase16(
+ "304402202984DDE7F0B566F081F7953D7212BF031ACBF8860FE114102E9512C4C8768C770220701" +
+ "13F4630B1DC3045E4A98DDD648CEBC31B12774F7B44A1B8123CD2C9F5CF18")
+ )
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV"))
+ .issuingChainIssue(
+ Issue.builder()
+ .currency("ETH")
+ .issuer(Address.of("rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"))
+ .build()
+ )
+ .build()
+ )
+ .build();
+
+ String expectedBinary = "12002C228000000024000000016140000000000F424068400000000000000A601D4000000000002" +
+ "71073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD0207446304402202984DDE7F0B566F0" +
+ "81F7953D7212BF031ACBF8860FE114102E9512C4C8768C77022070113F4630B1DC3045E4A98DDD648CEBC31B12774F7B44A1B" +
+ "8123CD2C9F5CF188114B5F762798A53D543A014CAF8B297CFF8F2F937E88314AF80285F637EE4AF3C20378F9DFB12511ACB8D" +
+ "27011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E" +
+ "785DC231A1058A05E56E3F09CF4E60000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C";
+
+ assertSerializesAndDeserializes(commit, expectedBinary);
+ }
+
+ @Test
+ void serializeXChainAddAccountCreateAttestation() throws JsonProcessingException {
+ XChainAddAccountCreateAttestation attestation = XChainAddAccountCreateAttestation.builder()
+ .account(Address.of("r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT"))
+ .otherChainSource(Address.of("raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym"))
+ .destination(Address.of("rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi"))
+ .amount(XrpCurrencyAmount.ofDrops(10000000))
+ .publicKey(
+ PublicKey.fromBase16EncodedPublicKey("ED1F4A024ACFEBDB6C7AA88DEDE3364E060487EA31B14CC9E0D610D152B31AADC2")
+ )
+ .signature(
+ Signature.fromBase16("EEFCFA3DC2AB4AB7C4D2EBBC168CB621A11B82BABD86534DFC8EFA72439A49662" +
+ "D744073CD848E7A587A95B35162CDF9A69BB237E72C9537A987F5B8C394F30D")
+ )
+ .wasLockingChainSend(true)
+ .attestationRewardAccount(Address.of("r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT"))
+ .attestationSignerAccount(Address.of("r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT"))
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.valueOf("ffffffffffffffff", 16)))
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .fee(XrpCurrencyAmount.ofDrops(20))
+ .sequence(UnsignedInteger.valueOf(5))
+ .lastLedgerSequence(UnsignedInteger.valueOf(13))
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("EDF54108BA2E0A0D3DC2AE3897F8BE0EFE776AE8D0F9FB0D0B9D64233084A8DDD1")
+ )
+ .transactionSignature(
+ Signature.fromBase16("03E74AEF1F585F156786429D2FC87A89E5C6B5A56D68BFC9A6A329F3AC67CBF" +
+ "2B6958283C663A4522278CA162C69B23CF75149AF022B410EA0508C16F4205800")
+ )
+ .build();
+
+ String expectedBinary = "12002E2400000005201B0000000D3015FFFFFFFFFFFFFFFF61400000000098968068400000000000001" +
+ "4601D40000000000000647121ED1F4A024ACFEBDB6C7AA88DEDE3364E060487EA31B14CC9E0D610D152B31AADC27321EDF54108BA" +
+ "2E0A0D3DC2AE3897F8BE0EFE776AE8D0F9FB0D0B9D64233084A8DDD1744003E74AEF1F585F156786429D2FC87A89E5C6B5A56D68B" +
+ "FC9A6A329F3AC67CBF2B6958283C663A4522278CA162C69B23CF75149AF022B410EA0508C16F42058007640EEFCFA3DC2AB4AB7C4" +
+ "D2EBBC168CB621A11B82BABD86534DFC8EFA72439A49662D744073CD848E7A587A95B35162CDF9A69BB237E72C9537A987F5B8C39" +
+ "4F30D81145E7A3E3D7200A794FA801C66CE3775B6416EE4128314C15F113E49BCC4B9FFF43CD0366C23ACD82F75638012143FD9ED" +
+ "9A79DEA67CB5D585111FEF0A29203FA0408014145E7A3E3D7200A794FA801C66CE3775B6416EE4128015145E7A3E3D7200A794FA8" +
+ "01C66CE3775B6416EE4120010130101191486F0B1126CE1205E59FDFDD2661A9FB7505CA70F000000000000000000000000000000" +
+ "000000000014B5F762798A53D543A014CAF8B297CFF8F2F937E80000000000000000000000000000000000000000";
+
+ assertSerializesAndDeserializes(attestation, expectedBinary);
+ }
+
+ @Test
+ void serializeXChainAddClaimAttestation() throws JsonProcessingException {
+ XChainAddClaimAttestation attestation = XChainAddClaimAttestation.builder()
+ .account(Address.of("rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3"))
+ .amount(XrpCurrencyAmount.ofDrops(10000000))
+ .attestationRewardAccount(Address.of("rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3"))
+ .attestationSignerAccount(Address.of("rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3"))
+ .destination(Address.of("rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi"))
+ .fee(XrpCurrencyAmount.ofDrops(20))
+ .lastLedgerSequence(UnsignedInteger.valueOf(19))
+ .otherChainSource(Address.of("raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym"))
+ .sequence(UnsignedInteger.valueOf(9))
+ .publicKey(
+ PublicKey.fromBase16EncodedPublicKey("ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E1136")
+ )
+ .signature(
+ Signature.fromBase16("7C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44" +
+ "528FE99AA50E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C")
+ )
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C")
+ )
+ .wasLockingChainSend(true)
+ .xChainBridge(
+ XChainBridge.builder()
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .lockingChainDoor(Address.of("rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg"))
+ .lockingChainIssue(Issue.XRP)
+ .build()
+ )
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.MAX_VALUE))
+ .transactionSignature(
+ Signature.fromBase16("D0423649E48A44F181262CF5FC08A68E7FA5CD9E55843E4F09014B76E602574" +
+ "741E8553383A4B43CABD194BB96713647FC0B885BE248E4FFA068FA3E6994CF04")
+ )
+ .build();
+
+ String expectedBinary = "12002D2400000009201B000000133014FFFFFFFFFFFFFFFF614000000000989680684000000000000014" +
+ "7121ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E11367321ED0406B134786FE0751717226657F7BF" +
+ "8AFE96442C05D28ACEC66FB64852BA604C7440D0423649E48A44F181262CF5FC08A68E7FA5CD9E55843E4F09014B76E602574741E8" +
+ "553383A4B43CABD194BB96713647FC0B885BE248E4FFA068FA3E6994CF0476407C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2" +
+ "A049474275153D9D4DD44528FE99AA50E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C81141F30A4D728AB98B0" +
+ "950EC3B9815E6C8D43A7D5598314C15F113E49BCC4B9FFF43CD0366C23ACD82F75638012143FD9ED9A79DEA67CB5D585111FEF0A29" +
+ "203FA0408014141F30A4D728AB98B0950EC3B9815E6C8D43A7D5598015141F30A4D728AB98B0950EC3B9815E6C8D43A7D559001013" +
+ "0101191486F0B1126CE1205E59FDFDD2661A9FB7505CA70F000000000000000000000000000000000000000014B5F762798A53D543" +
+ "A014CAF8B297CFF8F2F937E80000000000000000000000000000000000000000";
+
+ assertSerializesAndDeserializes(attestation, expectedBinary);
+ }
+
+ @Test
+ void serializeXChainClaim() throws JsonProcessingException {
+ XChainClaim claim = XChainClaim.builder()
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .sequence(UnsignedInteger.ONE)
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020")
+ )
+ .amount(XrpCurrencyAmount.ofDrops(10000))
+ .transactionSignature(
+ Signature.fromBase16("30440220445F7469FDA401787D9EE8A9B6E24DFF81E94F4C09FD311D2C0" +
+ "A58FCC02C684A022029E2EF34A5EA35F50D5BB57AC6320AD3AE12C13C8D1379B255A486D72CED142E")
+ )
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.MAX_VALUE))
+ .destination(Address.of("r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV"))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .build();
+
+ String expectedBinary = "12002B228000000024000000013014FFFFFFFFFFFFFFFF61400000000000271068400000000000000A" +
+ "73210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020744630440220445F7469FDA401787D9EE8" +
+ "A9B6E24DFF81E94F4C09FD311D2C0A58FCC02C684A022029E2EF34A5EA35F50D5BB57AC6320AD3AE12C13C8D1379B255A486D72C" +
+ "ED142E8114B5F762798A53D543A014CAF8B297CFF8F2F937E88314550FC62003E785DC231A1058A05E56E3F09CF4E6011914AF80" +
+ "285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05" +
+ "E56E3F09CF4E60000000000000000000000000000000000000000";
+
+ assertSerializesAndDeserializes(claim, expectedBinary);
+ }
+
+ @Test
+ void serializeXChainCommit() throws JsonProcessingException {
+ XChainCommit commit = XChainCommit.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .amount(XrpCurrencyAmount.ofDrops(10000))
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.MAX_VALUE))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020")
+ )
+ .transactionSignature(
+ Signature.fromBase16("3043021F177323F0D93612C82A4393A99B23905A7E675753FD80C52997AFA" +
+ "B13F5F9D002203BFFAF457E90BDA65AABE8F8762BD96162FAD98A0C030CCD69B06EE9B12BBFFE")
+ )
+ .build();
+
+ String expectedBinary = "12002A228000000024000000013014FFFFFFFFFFFFFFFF6140000000000027106840000000000000" +
+ "0A73210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02074453043021F177323F0D93612C82A" +
+ "4393A99B23905A7E675753FD80C52997AFAB13F5F9D002203BFFAF457E90BDA65AABE8F8762BD96162FAD98A0C030CCD69B06E" +
+ "E9B12BBFFE8114B5F762798A53D543A014CAF8B297CFF8F2F937E8011914AF80285F637EE4AF3C20378F9DFB12511ACB8D2700" +
+ "0000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000" +
+ "000000000000000000";
+
+ assertSerializesAndDeserializes(commit, expectedBinary);
+ }
+
+ @Test
+ void serializeXChainCreateBridge() throws JsonProcessingException {
+ XChainCreateBridge createBridge = XChainCreateBridge.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .signatureReward(XrpCurrencyAmount.ofDrops(1000))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .minAccountCreateAmount(XrpCurrencyAmount.ofDrops(10000))
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020")
+ )
+ .transactionSignature(
+ Signature.fromBase16("30440220101BCA4B5B5A37C6F44480F9A34752C9AA8B2CDF5AD47E3CB424DEDC" +
+ "21C06DB702206EEB257E82A89B1F46A0A2C7F070B0BD181D980FF86FE4269E369F6FC7A27091")
+ )
+ .flags(TransactionFlags.UNSET)
+ .build();
+
+ String binary = "1200302200000000240000000168400000000000000A601D40000000000003E8601E40000000000027" +
+ "1073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020744630440220101BCA4B5B5A" +
+ "37C6F44480F9A34752C9AA8B2CDF5AD47E3CB424DEDC21C06DB702206EEB257E82A89B1F46A0A2C7F070B0BD181D980F" +
+ "F86FE4269E369F6FC7A270918114B5F762798A53D543A014CAF8B297CFF8F2F937E8011914AF80285F637EE4AF3C2037" +
+ "8F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09C" +
+ "F4E60000000000000000000000000000000000000000";
+
+ assertSerializesAndDeserializes(createBridge, binary);
+ }
+
+ @Test
+ void serializeXChainCreateClaimId() throws JsonProcessingException {
+ XChainCreateClaimId claimId = XChainCreateClaimId.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .otherChainSource(Address.of("rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL"))
+ .signatureReward(XrpCurrencyAmount.ofDrops(10000))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020")
+ )
+ .transactionSignature(
+ Signature.fromBase16("30440220247B20A1B9C48E21A374CB9B3E1FE2A7C528151868DF8D307E9FBE" +
+ "15237E531A02207C20C092DDCC525E583EF4AB7CB91E862A6DED19426997D3F0A2C84E2BE8C5DD")
+ )
+ .build();
+
+ String binary = "1200292280000000240000000168400000000000000A601D400000000000271073210330E7FC9D56BB25D68" +
+ "93BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020744630440220247B20A1B9C48E21A374CB9B3E1FE2A7C528151868" +
+ "DF8D307E9FBE15237E531A02207C20C092DDCC525E583EF4AB7CB91E862A6DED19426997D3F0A2C84E2BE8C5DD8114B5F7627" +
+ "98A53D543A014CAF8B297CFF8F2F937E8801214AF80285F637EE4AF3C20378F9DFB12511ACB8D27011914AF80285F637EE4AF" +
+ "3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F0" +
+ "9CF4E60000000000000000000000000000000000000000";
+
+ assertSerializesAndDeserializes(claimId, binary);
+ }
+
+ @Test
+ void serializeXChainModifyBridge() throws JsonProcessingException {
+ XChainModifyBridge transaction = XChainModifyBridge.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .signatureReward(XrpCurrencyAmount.ofDrops(1000))
+ .minAccountCreateAmount(XrpCurrencyAmount.ofDrops(10000))
+ .flags(XChainModifyBridgeFlags.UNSET)
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020")
+ )
+ .transactionSignature(
+ Signature.fromBase16("3045022100D2CABC1B0E0635A8EE2E6554F6D474C49BC292C995C5C9F83179F" +
+ "4A60634B04C02205D1DB569D9593136F2FBEA7140010C8F46794D653AFDBEA8D30B8750BA4805E5")
+ )
+ .build();
+
+ String binary = "12002F2200000000240000000168400000000000000A601D40000000000003E8601E40000000000027107" +
+ "3210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02074473045022100D2CABC1B0E0635A8E" +
+ "E2E6554F6D474C49BC292C995C5C9F83179F4A60634B04C02205D1DB569D9593136F2FBEA7140010C8F46794D653AFDBEA8D" +
+ "30B8750BA4805E58114B5F762798A53D543A014CAF8B297CFF8F2F937E8011914AF80285F637EE4AF3C20378F9DFB12511AC" +
+ "B8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000" +
+ "000000000000000000000000000";
+
+ assertSerializesAndDeserializes(transaction, binary);
+ }
+
private void assertSerializesAndDeserializes(
T transaction,
String expectedBinary
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/types/UInt64TypeUnitTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/types/UInt64TypeUnitTest.java
index 849ab6cdd..e162389b0 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/types/UInt64TypeUnitTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/types/UInt64TypeUnitTest.java
@@ -41,11 +41,11 @@ void decode() {
@Test
void encode() {
- assertThat(codec.fromJson("0").toHex()).isEqualTo("0000000000000000");
- assertThat(codec.fromJson("15").toHex()).isEqualTo("000000000000000F");
- assertThat(codec.fromJson("65535").toHex()).isEqualTo("000000000000FFFF");
- assertThat(codec.fromJson("4294967295").toHex()).isEqualTo("00000000FFFFFFFF");
- assertThat(codec.fromJson(maxUint64.toString()).toHex()).isEqualTo("FFFFFFFFFFFFFFFF");
+ assertThat(codec.fromJson("\"0\"").toHex()).isEqualTo("0000000000000000");
+ assertThat(codec.fromJson("\"F\"").toHex()).isEqualTo("000000000000000F");
+ assertThat(codec.fromJson("\"FFFF\"").toHex()).isEqualTo("000000000000FFFF");
+ assertThat(codec.fromJson("\"FFFFFFFF\"").toHex()).isEqualTo("00000000FFFFFFFF");
+ assertThat(codec.fromJson("\"FFFFFFFFFFFFFFFF\"").toHex()).isEqualTo("FFFFFFFFFFFFFFFF");
}
@Test
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/AbstractSignatureServiceTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/AbstractSignatureServiceTest.java
index 03abb1692..aec228279 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/AbstractSignatureServiceTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/AbstractSignatureServiceTest.java
@@ -41,6 +41,7 @@
import org.xrpl.xrpl4j.crypto.keys.PrivateKeyable;
import org.xrpl.xrpl4j.crypto.keys.PublicKey;
import org.xrpl.xrpl4j.model.client.channels.UnsignedClaim;
+import org.xrpl.xrpl4j.model.ledger.Attestation;
import org.xrpl.xrpl4j.model.transactions.Signer;
import org.xrpl.xrpl4j.model.transactions.Transaction;
@@ -268,6 +269,34 @@ public void signUnsignedClaimEd25519() {
verifyNoMoreInteractions(signatureUtilsMock);
}
+ ///////////////////
+ // Sign (privateKey, Attestation)
+ ///////////////////
+
+ @Test
+ public void signAttestationWithNullPrivateKey() {
+ assertThrows(NullPointerException.class, () -> signatureService.sign(null, mock(Attestation.class)));
+ }
+
+ @Test
+ public void signAttestationWithNullUnsignedClaim() {
+ assertThrows(NullPointerException.class,
+ () -> signatureService.sign(TestConstants.getEdPrivateKey(), (Attestation) null));
+ }
+
+ @Test
+ public void signAttestationEd25519() {
+ Attestation unsignedAttestationMock = mock(Attestation.class);
+ when(signatureUtilsMock.toSignableBytes(unsignedAttestationMock)).thenReturn(UnsignedByteArray.empty());
+
+ Signature actualSignature = signatureService.sign(TestConstants.getEdPrivateKey(), unsignedAttestationMock);
+ assertThat(actualSignature).isEqualTo(ed25519SignatureMock);
+
+ verify(signatureUtilsMock, times(0)).toMultiSignableBytes(any(), any());
+ verify(signatureUtilsMock).toSignableBytes(unsignedAttestationMock);
+ verifyNoMoreInteractions(signatureUtilsMock);
+ }
+
///////////////////
// verify
///////////////////
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/AbstractTransactionSignerTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/AbstractTransactionSignerTest.java
index 30a056588..2fada9ccb 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/AbstractTransactionSignerTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/AbstractTransactionSignerTest.java
@@ -42,6 +42,7 @@
import org.xrpl.xrpl4j.crypto.keys.PrivateKeyable;
import org.xrpl.xrpl4j.crypto.keys.PublicKey;
import org.xrpl.xrpl4j.model.client.channels.UnsignedClaim;
+import org.xrpl.xrpl4j.model.ledger.Attestation;
import org.xrpl.xrpl4j.model.transactions.Signer;
import org.xrpl.xrpl4j.model.transactions.Transaction;
@@ -183,6 +184,48 @@ void signUnsignedClaimSecp256k1() {
assertThat(actual).isEqualTo(secp256k1SignatureMock);
}
+ ///////////////////
+ // Sign (Attestation)
+ ///////////////////
+
+ @Test
+ void signAttestationWithNullMetadata() {
+ Attestation unsignedAttestationMock = mock(Attestation.class);
+ assertThrows(NullPointerException.class, () -> transactionSigner.sign(null, unsignedAttestationMock));
+ }
+
+ @Test
+ void signAttestationWithNullTransaction() {
+ assertThrows(NullPointerException.class,
+ () -> transactionSigner.sign(privateKeyableMock, (Attestation) null));
+ }
+
+ @Test
+ void signAttestationEd25519() {
+ keyType = KeyType.ED25519;
+ Attestation unsignedAttestationMock = mock(Attestation.class);
+ when(signatureUtilsMock.toSignableBytes(unsignedAttestationMock)).thenReturn(UnsignedByteArray.empty());
+
+ Signature actual = transactionSigner.sign(privateKeyableMock, unsignedAttestationMock);
+
+ verify(signatureUtilsMock).toSignableBytes(unsignedAttestationMock);
+ verifyNoMoreInteractions(signatureUtilsMock);
+ assertThat(actual).isEqualTo(ed25519SignatureMock);
+ }
+
+ @Test
+ void signAttestationClaimSecp256k1() {
+ keyType = KeyType.SECP256K1;
+ Attestation unsignedAttestationMock = mock(Attestation.class);
+ when(signatureUtilsMock.toSignableBytes(unsignedAttestationMock)).thenReturn(UnsignedByteArray.empty());
+
+ Signature actual = transactionSigner.sign(privateKeyableMock, unsignedAttestationMock);
+
+ verify(signatureUtilsMock).toSignableBytes(unsignedAttestationMock);
+ verifyNoMoreInteractions(signatureUtilsMock);
+ assertThat(actual).isEqualTo(secp256k1SignatureMock);
+ }
+
///////////////////
// MultiSign to Signature
///////////////////
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtilsTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtilsTest.java
index bd0441ff1..75e286c6e 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtilsTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtilsTest.java
@@ -31,6 +31,7 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
import com.fasterxml.jackson.core.JsonLocation;
import com.fasterxml.jackson.core.JsonParseException;
@@ -46,10 +47,13 @@
import org.xrpl.xrpl4j.codec.addresses.UnsignedByteArray;
import org.xrpl.xrpl4j.codec.binary.XrplBinaryCodec;
import org.xrpl.xrpl4j.crypto.keys.PublicKey;
+import org.xrpl.xrpl4j.model.AddressConstants;
import org.xrpl.xrpl4j.model.client.channels.UnsignedClaim;
import org.xrpl.xrpl4j.model.flags.AmmDepositFlags;
import org.xrpl.xrpl4j.model.flags.AmmWithdrawFlags;
import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+import org.xrpl.xrpl4j.model.ledger.AttestationClaim;
+import org.xrpl.xrpl4j.model.ledger.AttestationCreateAccount;
import org.xrpl.xrpl4j.model.ledger.AuthAccount;
import org.xrpl.xrpl4j.model.ledger.AuthAccountWrapper;
import org.xrpl.xrpl4j.model.ledger.Issue;
@@ -71,6 +75,10 @@
import org.xrpl.xrpl4j.model.transactions.EscrowCreate;
import org.xrpl.xrpl4j.model.transactions.EscrowFinish;
import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainAddClaimAttestation;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainBridge;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainClaim;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainCreateClaimId;
import org.xrpl.xrpl4j.model.transactions.IssuedCurrencyAmount;
import org.xrpl.xrpl4j.model.transactions.NfTokenAcceptOffer;
import org.xrpl.xrpl4j.model.transactions.NfTokenBurn;
@@ -91,6 +99,17 @@
import org.xrpl.xrpl4j.model.transactions.TradingFee;
import org.xrpl.xrpl4j.model.transactions.Transaction;
import org.xrpl.xrpl4j.model.transactions.TrustSet;
+import org.xrpl.xrpl4j.model.transactions.XChainAccountCreateCommit;
+import org.xrpl.xrpl4j.model.transactions.XChainAddAccountCreateAttestation;
+import org.xrpl.xrpl4j.model.transactions.XChainAddClaimAttestation;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainClaim;
+import org.xrpl.xrpl4j.model.transactions.XChainClaimId;
+import org.xrpl.xrpl4j.model.transactions.XChainCommit;
+import org.xrpl.xrpl4j.model.transactions.XChainCount;
+import org.xrpl.xrpl4j.model.transactions.XChainCreateBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainCreateClaimId;
+import org.xrpl.xrpl4j.model.transactions.XChainModifyBridge;
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
import java.util.ArrayList;
@@ -104,6 +123,17 @@
public class SignatureUtilsTest {
private static final String HEX_PUBLIC_KEY = "027535A4E90B2189CF9885563F45C4F454B3BFAB21930089C3878A9427B4D648D9";
+ public static final ImmutableXChainBridge XCHAIN_BRIDGE = XChainBridge.builder()
+ .lockingChainDoor(Address.of("rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(
+ Issue.builder()
+ .currency("TST")
+ .issuer(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .build()
+ )
+ .build();
PublicKey sourcePublicKey;
@@ -234,6 +264,180 @@ void unsignedClaimToSignableBytesActual() {
.isEqualTo("434C4D00ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD0000000000000001");
}
+ //////////////////
+ // toSignableBytes (AttestationClaim)
+ //////////////////
+
+ @Test
+ void attestationClaimToSignableBytesWhenNull() {
+ assertThrows(NullPointerException.class, () -> signatureUtils.toSignableBytes((AttestationClaim) null));
+ }
+
+ @Test
+ void attestationClaimToSignableBytes() throws JsonProcessingException {
+ when(xrplBinaryCodecMock.encode(any())).thenReturn("ABCD1234");
+ final AttestationClaim unsignedAttestation = AttestationClaim.builder()
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .otherChainSource(AddressConstants.GENESIS_ACCOUNT)
+ .amount(XrpCurrencyAmount.ofDrops(10))
+ .attestationRewardAccount(AddressConstants.GENESIS_ACCOUNT)
+ .wasLockingChainSend(true)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .destination(AddressConstants.GENESIS_ACCOUNT)
+ .build();
+ assertThat(signatureUtils.toSignableBytes(unsignedAttestation).hexValue()).isEqualTo("ABCD1234");
+
+ verify(objectMapperMock).writeValueAsString(any());
+ verifyNoMoreInteractions(objectMapperMock);
+ verify(xrplBinaryCodecMock).encode(any());
+ verifyNoMoreInteractions(xrplBinaryCodecMock);
+ }
+
+ @Test
+ public void attestationClaimToSignableBytesWithJsonException() throws JsonProcessingException {
+ final AttestationClaim unsignedAttestation = AttestationClaim.builder()
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .otherChainSource(AddressConstants.GENESIS_ACCOUNT)
+ .amount(XrpCurrencyAmount.ofDrops(10))
+ .attestationRewardAccount(AddressConstants.GENESIS_ACCOUNT)
+ .wasLockingChainSend(true)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .destination(AddressConstants.GENESIS_ACCOUNT)
+ .build();
+ doThrow(new JsonParseException(mock(JsonParser.class), "", mock(JsonLocation.class)))
+ .when(objectMapperMock).writeValueAsString(unsignedAttestation);
+ assertThrows(RuntimeException.class, () -> signatureUtils.toSignableBytes(unsignedAttestation));
+ }
+
+ @Test
+ void attestationClaimToSignableBytesActual() {
+ final AttestationClaim unsignedAttestation = AttestationClaim.builder()
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .otherChainSource(AddressConstants.GENESIS_ACCOUNT)
+ .amount(XrpCurrencyAmount.ofDrops(10))
+ .attestationRewardAccount(AddressConstants.GENESIS_ACCOUNT)
+ .wasLockingChainSend(true)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .destination(AddressConstants.GENESIS_ACCOUNT)
+ .build();
+ assertThat(SignatureUtils.getInstance().toSignableBytes(unsignedAttestation).hexValue())
+ .isEqualTo("3014000000000000000161400000000000000A8314B5F762798A53D543A014CAF8B297CFF8F2F937E" +
+ "8801214B5F762798A53D543A014CAF8B297CFF8F2F937E8801514B5F762798A53D543A014CAF8B297CFF8F2F937E8001013" +
+ "01011914B5F762798A53D543A014CAF8B297CFF8F2F937E8000000000000000000000000000000000000000014B5F762798" +
+ "A53D543A014CAF8B297CFF8F2F937E80000000000000000000000000000000000000000");
+ }
+
+ //////////////////
+ // toSignableBytes (AttestationCreateAccount)
+ //////////////////
+
+ @Test
+ void attestationCreateAccountToSignableBytesWhenNull() {
+ assertThrows(NullPointerException.class, () -> signatureUtils.toSignableBytes((AttestationCreateAccount) null));
+ }
+
+ @Test
+ void attestationCreateToSignableBytes() throws JsonProcessingException {
+ when(xrplBinaryCodecMock.encode(any())).thenReturn("ABCD1234");
+ final AttestationCreateAccount unsignedAttestation = AttestationCreateAccount.builder()
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .otherChainSource(AddressConstants.GENESIS_ACCOUNT)
+ .amount(XrpCurrencyAmount.ofDrops(10))
+ .attestationRewardAccount(AddressConstants.GENESIS_ACCOUNT)
+ .wasLockingChainSend(true)
+ .destination(AddressConstants.GENESIS_ACCOUNT)
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ONE))
+ .signatureReward(XrpCurrencyAmount.ofDrops(200))
+ .build();
+
+ assertThat(signatureUtils.toSignableBytes(unsignedAttestation).hexValue()).isEqualTo("ABCD1234");
+
+ verify(objectMapperMock).writeValueAsString(any());
+ verifyNoMoreInteractions(objectMapperMock);
+ verify(xrplBinaryCodecMock).encode(any());
+ verifyNoMoreInteractions(xrplBinaryCodecMock);
+ }
+
+ @Test
+ public void attestationCreateToSignableBytesWithJsonException() throws JsonProcessingException {
+ final AttestationCreateAccount unsignedAttestation = AttestationCreateAccount.builder()
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .otherChainSource(AddressConstants.GENESIS_ACCOUNT)
+ .amount(XrpCurrencyAmount.ofDrops(10))
+ .attestationRewardAccount(AddressConstants.GENESIS_ACCOUNT)
+ .wasLockingChainSend(true)
+ .destination(AddressConstants.GENESIS_ACCOUNT)
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ONE))
+ .signatureReward(XrpCurrencyAmount.ofDrops(200))
+ .build();
+
+ doThrow(new JsonParseException(mock(JsonParser.class), "", mock(JsonLocation.class)))
+ .when(objectMapperMock).writeValueAsString(unsignedAttestation);
+ assertThrows(RuntimeException.class, () -> signatureUtils.toSignableBytes(unsignedAttestation));
+ }
+
+ @Test
+ void attestationCreateToSignableBytesActual() {
+ final AttestationCreateAccount unsignedAttestation = AttestationCreateAccount.builder()
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .otherChainSource(AddressConstants.GENESIS_ACCOUNT)
+ .amount(XrpCurrencyAmount.ofDrops(10))
+ .attestationRewardAccount(AddressConstants.GENESIS_ACCOUNT)
+ .wasLockingChainSend(true)
+ .destination(AddressConstants.GENESIS_ACCOUNT)
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ONE))
+ .signatureReward(XrpCurrencyAmount.ofDrops(200))
+ .build();
+
+ assertThat(SignatureUtils.getInstance().toSignableBytes(unsignedAttestation).hexValue())
+ .isEqualTo("3015000000000000000161400000000000000A601D40000000000000C88314B5F762798A53D543A014C" +
+ "AF8B297CFF8F2F937E8801214B5F762798A53D543A014CAF8B297CFF8F2F937E8801514B5F762798A53D543A014CAF8B297CF" +
+ "F8F2F937E800101301011914B5F762798A53D543A014CAF8B297CFF8F2F937E80000000000000000000000000000000000000" +
+ "00014B5F762798A53D543A014CAF8B297CFF8F2F937E80000000000000000000000000000000000000000");
+ }
+
//////////////////
// toMultiSignableBytes
//////////////////
@@ -735,6 +939,147 @@ void addSignatureToClawback() {
addSignatureToTransactionHelper(clawback);
}
+ @Test
+ void addSignatureToXChainAccountCreateCommit() {
+ XChainAccountCreateCommit commit = XChainAccountCreateCommit.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .fee(XrpCurrencyAmount.ofDrops(1))
+ .sequence(UnsignedInteger.ONE)
+ .destination(Address.of("rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo"))
+ .amount(XrpCurrencyAmount.ofDrops(20000000))
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .signingPublicKey(sourcePublicKey)
+ .xChainBridge(XCHAIN_BRIDGE)
+ .build();
+
+ addSignatureToTransactionHelper(commit);
+ }
+
+ @Test
+ void addSignatureToXChainAddAccountCreateAttestation() {
+ XChainAddAccountCreateAttestation transaction = XChainAddAccountCreateAttestation.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .otherChainSource(Address.of("rUzB7yg1LcFa7m3q1hfrjr5w53vcWzNh3U"))
+ .destination(Address.of("rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd"))
+ .amount(XrpCurrencyAmount.ofDrops(2000000000))
+ .publicKey(sourcePublicKey)
+ .wasLockingChainSend(true)
+ .attestationRewardAccount(Address.of("rpFp36UHW6FpEcZjZqq5jSJWY6UCj3k4Es"))
+ .attestationSignerAccount(Address.of("rpWLegmW9WrFBzHUj7brhQNZzrxgLj9oxw"))
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.valueOf(2)))
+ .signatureReward(XrpCurrencyAmount.ofDrops(204))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .fee(XrpCurrencyAmount.ofDrops(20))
+ .sequence(UnsignedInteger.ONE)
+ .signingPublicKey(sourcePublicKey)
+ .signature(
+ Signature.fromBase16("F95675BA8FDA21030DE1B687937A79E8491CE51832D6BEEBC071484FA5AF5B8A0E" +
+ "9AFF11A4AA46F09ECFFB04C6A8DAE8284AF3ED8128C7D0046D842448478500")
+ )
+ .build();
+
+ addSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addSignatureToXChainAddClaimAttestation() {
+ XChainAddClaimAttestation transaction = XChainAddClaimAttestation.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .amount(XrpCurrencyAmount.ofDrops(10000000))
+ .attestationRewardAccount(Address.of("rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3"))
+ .attestationSignerAccount(Address.of("rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3"))
+ .destination(Address.of("rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi"))
+ .fee(XrpCurrencyAmount.ofDrops(20))
+ .lastLedgerSequence(UnsignedInteger.valueOf(19))
+ .otherChainSource(Address.of("raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym"))
+ .sequence(UnsignedInteger.valueOf(9))
+ .publicKey(sourcePublicKey)
+ .signingPublicKey(sourcePublicKey)
+ .signature(
+ Signature.fromBase16("F95675BA8FDA21030DE1B687937A79E8491CE51832D6BEEBC071484FA5AF5B8A0E" +
+ "9AFF11A4AA46F09ECFFB04C6A8DAE8284AF3ED8128C7D0046D842448478500")
+ )
+ .wasLockingChainSend(true)
+ .xChainBridge(XCHAIN_BRIDGE)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .build();
+
+ addSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addSignatureToXChainClaim() {
+ XChainClaim transaction = XChainClaim.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .fee(XrpCurrencyAmount.ofDrops(12))
+ .sequence(UnsignedInteger.ONE)
+ .signingPublicKey(sourcePublicKey)
+ .amount(XrpCurrencyAmount.ofDrops(10000))
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.valueOf(0x13F)))
+ .destination(Address.of("rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw"))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .build();
+
+ addSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addSignatureToXChainCommit() {
+ XChainCommit transaction = XChainCommit.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(sourcePublicKey.deriveAddress())
+ .amount(XrpCurrencyAmount.ofDrops(10000))
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.valueOf(0x13f)))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .signingPublicKey(sourcePublicKey)
+ .build();
+
+ addSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addSignatureToXChainCreateBridge() {
+ XChainCreateBridge transaction = XChainCreateBridge.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(sourcePublicKey.deriveAddress())
+ .signatureReward(XrpCurrencyAmount.ofDrops(200))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .signingPublicKey(sourcePublicKey)
+ .build();
+
+ addSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addSignatureToXChainCreateClaimId() {
+ XChainCreateClaimId transaction = XChainCreateClaimId.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(sourcePublicKey.deriveAddress())
+ .otherChainSource(Address.of("rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo"))
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .signingPublicKey(sourcePublicKey)
+ .build();
+
+ addSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addSignatureToXChainModifyBridge() {
+ XChainModifyBridge transaction = XChainModifyBridge.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(sourcePublicKey.deriveAddress())
+ .xChainBridge(XCHAIN_BRIDGE)
+ .signingPublicKey(sourcePublicKey)
+ .build();
+
+ addSignatureToTransactionHelper(transaction);
+ }
+
@Test
public void addSignatureToTransactionUnsupported() {
assertThrows(IllegalArgumentException.class, () -> addSignatureToTransactionHelper(transactionMock));
@@ -1195,6 +1540,139 @@ void addMultiSignatureToAmmDelete() {
addMultiSignatureToTransactionHelper(ammDelete);
}
+ @Test
+ void addMultiSignatureToXChainAccountCreateCommit() {
+ XChainAccountCreateCommit transaction = XChainAccountCreateCommit.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .fee(XrpCurrencyAmount.ofDrops(1))
+ .sequence(UnsignedInteger.ONE)
+ .destination(Address.of("rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo"))
+ .amount(XrpCurrencyAmount.ofDrops(20000000))
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .build();
+
+ addMultiSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addMultiSignatureToXChainAddAccountCreateAttestation() {
+ XChainAddAccountCreateAttestation transaction = XChainAddAccountCreateAttestation.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .otherChainSource(Address.of("rUzB7yg1LcFa7m3q1hfrjr5w53vcWzNh3U"))
+ .destination(Address.of("rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd"))
+ .amount(XrpCurrencyAmount.ofDrops(2000000000))
+ .publicKey(sourcePublicKey)
+ .wasLockingChainSend(true)
+ .attestationRewardAccount(Address.of("rpFp36UHW6FpEcZjZqq5jSJWY6UCj3k4Es"))
+ .attestationSignerAccount(Address.of("rpWLegmW9WrFBzHUj7brhQNZzrxgLj9oxw"))
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.valueOf(2)))
+ .signatureReward(XrpCurrencyAmount.ofDrops(204))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .fee(XrpCurrencyAmount.ofDrops(20))
+ .sequence(UnsignedInteger.ONE)
+ .signature(
+ Signature.fromBase16("F95675BA8FDA21030DE1B687937A79E8491CE51832D6BEEBC071484FA5AF5B8A0E" +
+ "9AFF11A4AA46F09ECFFB04C6A8DAE8284AF3ED8128C7D0046D842448478500")
+ )
+ .build();
+
+ addMultiSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addMultiSignatureToXChainAddClaimAttestation() {
+ XChainAddClaimAttestation transaction = XChainAddClaimAttestation.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .amount(XrpCurrencyAmount.ofDrops(10000000))
+ .attestationRewardAccount(Address.of("rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3"))
+ .attestationSignerAccount(Address.of("rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3"))
+ .destination(Address.of("rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi"))
+ .fee(XrpCurrencyAmount.ofDrops(20))
+ .lastLedgerSequence(UnsignedInteger.valueOf(19))
+ .otherChainSource(Address.of("raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym"))
+ .sequence(UnsignedInteger.valueOf(9))
+ .publicKey(sourcePublicKey)
+ .signature(
+ Signature.fromBase16("F95675BA8FDA21030DE1B687937A79E8491CE51832D6BEEBC071484FA5AF5B8A0E" +
+ "9AFF11A4AA46F09ECFFB04C6A8DAE8284AF3ED8128C7D0046D842448478500")
+ )
+ .wasLockingChainSend(true)
+ .xChainBridge(XCHAIN_BRIDGE)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .build();
+
+ addMultiSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addMultiSignatureToXChainClaim() {
+ XChainClaim transaction = XChainClaim.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .fee(XrpCurrencyAmount.ofDrops(12))
+ .sequence(UnsignedInteger.ONE)
+ .amount(XrpCurrencyAmount.ofDrops(10000))
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.valueOf(0x13F)))
+ .destination(Address.of("rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw"))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .build();
+
+ addMultiSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addMultiSignatureToXChainCommit() {
+ XChainCommit transaction = XChainCommit.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(sourcePublicKey.deriveAddress())
+ .amount(XrpCurrencyAmount.ofDrops(10000))
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.valueOf(0x13f)))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .build();
+
+ addMultiSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addMultiSignatureToXChainCreateBridge() {
+ XChainCreateBridge transaction = XChainCreateBridge.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(sourcePublicKey.deriveAddress())
+ .signatureReward(XrpCurrencyAmount.ofDrops(200))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .build();
+
+ addMultiSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addMultiSignatureToXChainCreateClaimId() {
+ XChainCreateClaimId transaction = XChainCreateClaimId.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(sourcePublicKey.deriveAddress())
+ .otherChainSource(Address.of("rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo"))
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .xChainBridge(XCHAIN_BRIDGE)
+ .build();
+
+ addMultiSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addMultiSignatureToXChainModifyBridge() {
+ XChainModifyBridge transaction = XChainModifyBridge.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(sourcePublicKey.deriveAddress())
+ .xChainBridge(XCHAIN_BRIDGE)
+ .build();
+
+ addMultiSignatureToTransactionHelper(transaction);
+ }
+
@Test
public void addMultiSignaturesToTransactionUnsupported() {
when(transactionMock.transactionSignature()).thenReturn(Optional.empty());
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/bc/BcDerivedKeySignatureServiceTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/bc/BcDerivedKeySignatureServiceTest.java
index 2d9db6f04..e407ae1c2 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/bc/BcDerivedKeySignatureServiceTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/bc/BcDerivedKeySignatureServiceTest.java
@@ -42,14 +42,21 @@
import org.xrpl.xrpl4j.crypto.keys.Seed;
import org.xrpl.xrpl4j.crypto.signing.Signature;
import org.xrpl.xrpl4j.crypto.signing.SingleSignedTransaction;
+import org.xrpl.xrpl4j.model.AddressConstants;
import org.xrpl.xrpl4j.model.client.channels.UnsignedClaim;
import org.xrpl.xrpl4j.model.flags.PaymentFlags;
import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+import org.xrpl.xrpl4j.model.ledger.AttestationClaim;
+import org.xrpl.xrpl4j.model.ledger.AttestationCreateAccount;
+import org.xrpl.xrpl4j.model.ledger.Issue;
import org.xrpl.xrpl4j.model.transactions.Address;
import org.xrpl.xrpl4j.model.transactions.Hash256;
import org.xrpl.xrpl4j.model.transactions.IssuedCurrencyAmount;
import org.xrpl.xrpl4j.model.transactions.Payment;
import org.xrpl.xrpl4j.model.transactions.Signer;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainClaimId;
+import org.xrpl.xrpl4j.model.transactions.XChainCount;
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
import java.nio.charset.StandardCharsets;
@@ -517,6 +524,200 @@ void signUnsignedClaimEc() {
.forEach(validSig -> assertThat(validSig).isTrue());
}
+ @Test
+ void signAttestationClaimEd() {
+ final PrivateKeyReference privateKeyReference = privateKeyReference("foo", KeyType.ED25519);
+
+ final AttestationClaim unsignedAttestation = AttestationClaim.builder()
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .otherChainSource(AddressConstants.GENESIS_ACCOUNT)
+ .amount(XrpCurrencyAmount.ofDrops(10))
+ .attestationRewardAccount(AddressConstants.GENESIS_ACCOUNT)
+ .wasLockingChainSend(true)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .destination(AddressConstants.GENESIS_ACCOUNT)
+ .build();
+
+ final ExecutorService pool = Executors.newFixedThreadPool(5);
+ final Callable signedTxCallable = () -> {
+ Signature signature = this.derivedKeySignatureService.sign(privateKeyReference, unsignedAttestation);
+ assertThat(signature).isNotNull();
+ assertThat(signature.base16Value()).isEqualTo(
+ "C436AA1F579C2ADCE04143A8BCF77C8A10BD2EA2ADD9989FD381AD65123C977294C248157686149D9D8552C2A35A90" +
+ "28D577B244CE079020372A229D06D03504"
+ );
+ return true;
+ };
+
+ final List> futureSeeds = new ArrayList<>();
+ for (int i = 0; i < 500; i++) {
+ futureSeeds.add(pool.submit(signedTxCallable));
+ }
+
+ futureSeeds.stream()
+ .map($ -> {
+ try {
+ return $.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ })
+ .forEach(validSig -> assertThat(validSig).isTrue());
+ }
+
+ @Test
+ void signAttestationClaimEc() {
+ final PrivateKeyReference privateKeyReference = privateKeyReference("foo", KeyType.SECP256K1);
+
+ final AttestationClaim unsignedAttestation = AttestationClaim.builder()
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .otherChainSource(AddressConstants.GENESIS_ACCOUNT)
+ .amount(XrpCurrencyAmount.ofDrops(10))
+ .attestationRewardAccount(AddressConstants.GENESIS_ACCOUNT)
+ .wasLockingChainSend(true)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .destination(AddressConstants.GENESIS_ACCOUNT)
+ .build();
+
+ final ExecutorService pool = Executors.newFixedThreadPool(5);
+ final Callable signedTxCallable = () -> {
+ Signature signature = this.derivedKeySignatureService.sign(privateKeyReference, unsignedAttestation);
+ assertThat(signature).isNotNull();
+ assertThat(signature.base16Value()).isEqualTo(
+ "30440220078E2379E68E59D60DFF4054FE0F988A95595E7A0DB2DB7215A3B7C03232CC7C022021BDB527050084BD9" +
+ "533BD21FAC0ABB63FD21754AC87C5F580AC583DDF1A9740"
+ );
+ return true;
+ };
+
+ final List> futureSeeds = new ArrayList<>();
+ for (int i = 0; i < 500; i++) {
+ futureSeeds.add(pool.submit(signedTxCallable));
+ }
+
+ futureSeeds.stream()
+ .map($ -> {
+ try {
+ return $.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ })
+ .forEach(validSig -> assertThat(validSig).isTrue());
+ }
+
+ @Test
+ void signAttestationCreateAccountEd() {
+ final PrivateKeyReference privateKeyReference = privateKeyReference("foo", KeyType.ED25519);
+
+ final AttestationCreateAccount unsignedAttestation = AttestationCreateAccount.builder()
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .otherChainSource(AddressConstants.GENESIS_ACCOUNT)
+ .amount(XrpCurrencyAmount.ofDrops(10))
+ .attestationRewardAccount(AddressConstants.GENESIS_ACCOUNT)
+ .wasLockingChainSend(true)
+ .destination(AddressConstants.GENESIS_ACCOUNT)
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ONE))
+ .signatureReward(XrpCurrencyAmount.ofDrops(200))
+ .build();
+
+ final ExecutorService pool = Executors.newFixedThreadPool(5);
+ final Callable signedTxCallable = () -> {
+ Signature signature = this.derivedKeySignatureService.sign(privateKeyReference, unsignedAttestation);
+ assertThat(signature).isNotNull();
+ assertThat(signature.base16Value()).isEqualTo(
+ "D44CFFD228B1A17DEC47433F4E14DD3FD844513129EB68725D45A3D9FA89AFDD45C433579BC9B31FFC109181" +
+ "AF565BD63B49011BC6784F9861C33BD7B1235007"
+ );
+ return true;
+ };
+
+ final List> futureSeeds = new ArrayList<>();
+ for (int i = 0; i < 500; i++) {
+ futureSeeds.add(pool.submit(signedTxCallable));
+ }
+
+ futureSeeds.stream()
+ .map($ -> {
+ try {
+ return $.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ })
+ .forEach(validSig -> assertThat(validSig).isTrue());
+ }
+
+ @Test
+ void signAttestationCreateAccountEc() {
+ final PrivateKeyReference privateKeyReference = privateKeyReference("foo", KeyType.SECP256K1);
+
+ final AttestationCreateAccount unsignedAttestation = AttestationCreateAccount.builder()
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .otherChainSource(AddressConstants.GENESIS_ACCOUNT)
+ .amount(XrpCurrencyAmount.ofDrops(10))
+ .attestationRewardAccount(AddressConstants.GENESIS_ACCOUNT)
+ .wasLockingChainSend(true)
+ .destination(AddressConstants.GENESIS_ACCOUNT)
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ONE))
+ .signatureReward(XrpCurrencyAmount.ofDrops(200))
+ .build();
+
+ final ExecutorService pool = Executors.newFixedThreadPool(5);
+ final Callable signedTxCallable = () -> {
+ Signature signature = this.derivedKeySignatureService.sign(privateKeyReference, unsignedAttestation);
+ assertThat(signature).isNotNull();
+ assertThat(signature.base16Value()).isEqualTo(
+ "3044022024A4E54773DCC751082D2F9DAEC60C06960E2DE40BC2896B9690D917DA310EB902202547C4569E817" +
+ "C4505C4B672D65CF24B93B3EB6748564E819EB26E8ED5A20790"
+ );
+ return true;
+ };
+
+ final List> futureSeeds = new ArrayList<>();
+ for (int i = 0; i < 500; i++) {
+ futureSeeds.add(pool.submit(signedTxCallable));
+ }
+
+ futureSeeds.stream()
+ .map($ -> {
+ try {
+ return $.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ })
+ .forEach(validSig -> assertThat(validSig).isTrue());
+ }
+
@Test
void generateEd25519XrplSeed() {
final ExecutorService pool = Executors.newFixedThreadPool(5);
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParamsTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParamsTest.java
index 1955540d3..9f3c3d1d8 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParamsTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParamsTest.java
@@ -16,6 +16,7 @@
import org.xrpl.xrpl4j.model.client.ledger.RippleStateLedgerEntryParams.RippleStateAccounts;
import org.xrpl.xrpl4j.model.ledger.AccountRootObject;
import org.xrpl.xrpl4j.model.ledger.AmmObject;
+import org.xrpl.xrpl4j.model.ledger.BridgeObject;
import org.xrpl.xrpl4j.model.ledger.CheckObject;
import org.xrpl.xrpl4j.model.ledger.DepositPreAuthObject;
import org.xrpl.xrpl4j.model.ledger.EscrowObject;
@@ -27,6 +28,8 @@
import org.xrpl.xrpl4j.model.ledger.RippleStateObject;
import org.xrpl.xrpl4j.model.ledger.TicketObject;
import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.ImmutableXChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
class LedgerEntryRequestParamsTest extends AbstractJsonTest {
@@ -47,6 +50,8 @@ void testTypedIndexParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = String.format("{\n" +
" \"index\": \"%s\",\n" +
@@ -80,6 +85,8 @@ void testUntypedIndexParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = String.format("{\n" +
" \"index\": \"%s\",\n" +
@@ -108,6 +115,8 @@ void testAccountRootParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = String.format("{\n" +
" \"account_root\": \"%s\",\n" +
@@ -144,6 +153,8 @@ void testAmmParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = "{\n" +
" \"amm\": {\n" +
@@ -185,6 +196,8 @@ void testOfferParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = "{\n" +
" \"offer\": {\n" +
@@ -224,6 +237,8 @@ void testRippleStateParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = "{\n" +
" \"ripple_state\": {\n" +
@@ -256,6 +271,8 @@ void testCheckParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = String.format("{\n" +
" \"check\": \"%s\",\n" +
@@ -288,6 +305,8 @@ void testEscrowParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = "{\n" +
" \"escrow\": {\n" +
@@ -319,6 +338,8 @@ void testPaymentChannelParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = String.format("{\n" +
" \"payment_channel\": \"%s\",\n" +
@@ -352,6 +373,8 @@ void testDepositPreAuthParams() throws JSONException, JsonProcessingException {
assertThat(params.paymentChannel()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = "{\n" +
" \"deposit_preauth\": {\n" +
@@ -388,6 +411,8 @@ void testTicketParams() throws JSONException, JsonProcessingException {
assertThat(params.paymentChannel()).isEmpty();
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = "{\n" +
" \"ticket\": {\n" +
@@ -420,6 +445,8 @@ void testNftPageParams() throws JSONException, JsonProcessingException {
assertThat(params.paymentChannel()).isEmpty();
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
String json = String.format("{\n" +
" \"nft_page\": \"%s\",\n" +
@@ -429,4 +456,43 @@ void testNftPageParams() throws JSONException, JsonProcessingException {
assertCanSerializeAndDeserialize(params, json);
}
+
+ @Test
+ void testBridgeParams() throws JSONException, JsonProcessingException {
+ XChainBridge bridge = XChainBridge.builder()
+ .lockingChainDoor(ED_ADDRESS)
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(ED_ADDRESS)
+ .issuingChainIssue(Issue.XRP)
+ .build();
+ LedgerEntryRequestParams params = LedgerEntryRequestParams.bridge(
+ ED_ADDRESS,
+ bridge,
+ LedgerSpecifier.VALIDATED
+ );
+ assertThat(params.bridgeAccount()).isNotEmpty().get().isEqualTo(ED_ADDRESS);
+ assertThat(params.bridge()).isNotEmpty().get().isEqualTo(bridge);
+ assertThat(params.ledgerObjectClass()).isEqualTo(BridgeObject.class);
+
+ assertThat(params.index()).isEmpty();
+ assertThat(params.accountRoot()).isEmpty();
+ assertThat(params.amm()).isEmpty();
+ assertThat(params.offer()).isEmpty();
+ assertThat(params.rippleState()).isEmpty();
+ assertThat(params.check()).isEmpty();
+ assertThat(params.escrow()).isEmpty();
+ assertThat(params.paymentChannel()).isEmpty();
+ assertThat(params.depositPreAuth()).isEmpty();
+ assertThat(params.ticket()).isEmpty();
+ assertThat(params.nftPage()).isEmpty();
+
+ String json = String.format("{\n" +
+ " \"bridge_account\": \"%s\",\n" +
+ " \"bridge\": %s,\n" +
+ " \"binary\": false,\n" +
+ " \"ledger_index\": \"validated\"\n" +
+ " }", ED_ADDRESS, objectMapper.writeValueAsString(bridge));
+
+ assertCanSerializeAndDeserialize(params, json);
+ }
}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/flags/XChainModifyBridgeFlagsTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/flags/XChainModifyBridgeFlagsTest.java
new file mode 100644
index 000000000..d647ce82a
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/flags/XChainModifyBridgeFlagsTest.java
@@ -0,0 +1,89 @@
+package org.xrpl.xrpl4j.model.flags;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+class XChainModifyBridgeFlagsTest extends AbstractFlagsTest {
+
+ public static Stream data() {
+ return getBooleanCombinations(1);
+ }
+
+ @ParameterizedTest
+ @MethodSource("data")
+ public void testFlagsConstructionWithIndividualFlags(
+ boolean tfClearAccountCreateAmount
+ ) {
+ XChainModifyBridgeFlags flags = XChainModifyBridgeFlags.builder()
+ .tfClearAccountCreateAmount(tfClearAccountCreateAmount)
+ .build();
+
+ assertThat(flags.getValue())
+ .isEqualTo(getExpectedFlags(tfClearAccountCreateAmount));
+ }
+
+ @ParameterizedTest
+ @MethodSource("data")
+ void testDeriveIndividualFlagsFromFlags(
+ boolean tfClearAccountCreateAmount
+ ) {
+ long expectedFlags = getExpectedFlags(tfClearAccountCreateAmount);
+ XChainModifyBridgeFlags flags = XChainModifyBridgeFlags.of(expectedFlags);
+
+ assertThat(flags.getValue()).isEqualTo(expectedFlags);
+
+ assertThat(flags.tfFullyCanonicalSig()).isTrue();
+ assertThat(flags.tfClearAccountCreateAmount()).isEqualTo(tfClearAccountCreateAmount);
+ }
+
+ @Test
+ void testEmptyFlags() {
+ XChainModifyBridgeFlags flags = XChainModifyBridgeFlags.empty();
+ assertThat(flags.isEmpty()).isTrue();
+ assertThat(flags.tfFullyCanonicalSig()).isFalse();
+ assertThat(flags.tfClearAccountCreateAmount()).isFalse();
+ assertThat(flags.getValue()).isEqualTo(0L);
+ }
+
+ @ParameterizedTest
+ @MethodSource("data")
+ void testJson(
+ boolean tfClearAccountCreateAmount
+ ) throws JSONException, JsonProcessingException {
+ XChainModifyBridgeFlags flags = XChainModifyBridgeFlags.builder()
+ .tfClearAccountCreateAmount(tfClearAccountCreateAmount)
+ .build();
+
+ TransactionFlagsWrapper wrapper = TransactionFlagsWrapper.of(flags);
+ String json = String.format("{\n" +
+ " \"flags\": %s\n" +
+ "}", flags.getValue());
+
+ assertCanSerializeAndDeserialize(wrapper, json);
+ }
+
+ @Test
+ void testEmptyJson() throws JSONException, JsonProcessingException {
+ XChainModifyBridgeFlags flags = XChainModifyBridgeFlags.empty();
+ TransactionFlagsWrapper wrapper = TransactionFlagsWrapper.of(flags);
+ String json = "{\n" +
+ "}";
+
+ assertCanSerializeAndDeserialize(wrapper, json);
+ }
+
+ private long getExpectedFlags(
+ boolean tfClearAccountCreateAmount
+ ) {
+ return (XChainModifyBridgeFlags.FULLY_CANONICAL_SIG.getValue()) |
+ (tfClearAccountCreateAmount ? XChainModifyBridgeFlags.CLEAR_ACCOUNT_CREATE_AMOUNT.getValue() : 0L);
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/BridgeObjectTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/BridgeObjectTest.java
new file mode 100644
index 000000000..8698c7a3e
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/BridgeObjectTest.java
@@ -0,0 +1,119 @@
+package org.xrpl.xrpl4j.model.ledger;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainClaimId;
+import org.xrpl.xrpl4j.model.transactions.XChainCount;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+class BridgeObjectTest extends AbstractJsonTest {
+
+ @Test
+ void testFullyPopulatedJson() throws JSONException, JsonProcessingException {
+ BridgeObject bridge = BridgeObject.builder()
+ .account(Address.of("r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC"))
+ .minAccountCreateAmount(XrpCurrencyAmount.ofDrops(2000000000))
+ .ownerNode("0")
+ .previousTransactionId(Hash256.of("67A8A1B36C1B97BE3AAB6B19CB3A3069034877DE917FD1A71919EAE7548E5636"))
+ .previousTransactionLedgerSequence(UnsignedInteger.valueOf(102))
+ .signatureReward(XrpCurrencyAmount.ofDrops(204))
+ .xChainAccountClaimCount(XChainCount.of(UnsignedLong.ZERO))
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ZERO))
+ .xChainBridge(
+ XChainBridge.builder()
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .lockingChainDoor(Address.of("r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC"))
+ .lockingChainIssue(Issue.XRP)
+ .build()
+ )
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .index(Hash256.of("9F2C9E23343852036AFD323025A8506018ABF9D4DBAA746D61BF1CFB5C297D10"))
+ .build();
+
+ String json = "\n" +
+ "{\n" +
+ " \"Account\": \"r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC\",\n" +
+ " \"Flags\": 0,\n" +
+ " \"LedgerEntryType\": \"Bridge\",\n" +
+ " \"MinAccountCreateAmount\": \"2000000000\",\n" +
+ " \"OwnerNode\": \"0\",\n" +
+ " \"PreviousTxnID\": \"67A8A1B36C1B97BE3AAB6B19CB3A3069034877DE917FD1A71919EAE7548E5636\",\n" +
+ " \"PreviousTxnLgrSeq\": 102,\n" +
+ " \"SignatureReward\": \"204\",\n" +
+ " \"XChainAccountClaimCount\": \"0\",\n" +
+ " \"XChainAccountCreateCount\": \"0\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"LockingChainDoor\": \"r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"XChainClaimID\": \"1\",\n" +
+ " \"index\": \"9F2C9E23343852036AFD323025A8506018ABF9D4DBAA746D61BF1CFB5C297D10\"\n" +
+ "}";
+
+ assertCanSerializeAndDeserialize(bridge, json);
+ }
+
+ @Test
+ void testJsonWithEmptyAccountCreateAmount() throws JSONException, JsonProcessingException {
+ BridgeObject bridge = BridgeObject.builder()
+ .account(Address.of("r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC"))
+ .ownerNode("0")
+ .previousTransactionId(Hash256.of("67A8A1B36C1B97BE3AAB6B19CB3A3069034877DE917FD1A71919EAE7548E5636"))
+ .previousTransactionLedgerSequence(UnsignedInteger.valueOf(102))
+ .signatureReward(XrpCurrencyAmount.ofDrops(204))
+ .xChainAccountClaimCount(XChainCount.of(UnsignedLong.ZERO))
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ZERO))
+ .xChainBridge(
+ XChainBridge.builder()
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .lockingChainDoor(Address.of("r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC"))
+ .lockingChainIssue(Issue.XRP)
+ .build()
+ )
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .index(Hash256.of("9F2C9E23343852036AFD323025A8506018ABF9D4DBAA746D61BF1CFB5C297D10"))
+ .build();
+
+ String json = "\n" +
+ "{\n" +
+ " \"Account\": \"r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC\",\n" +
+ " \"Flags\": 0,\n" +
+ " \"LedgerEntryType\": \"Bridge\",\n" +
+ " \"OwnerNode\": \"0\",\n" +
+ " \"PreviousTxnID\": \"67A8A1B36C1B97BE3AAB6B19CB3A3069034877DE917FD1A71919EAE7548E5636\",\n" +
+ " \"PreviousTxnLgrSeq\": 102,\n" +
+ " \"SignatureReward\": \"204\",\n" +
+ " \"XChainAccountClaimCount\": \"0\",\n" +
+ " \"XChainAccountCreateCount\": \"0\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"LockingChainDoor\": \"r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"XChainClaimID\": \"1\",\n" +
+ " \"index\": \"9F2C9E23343852036AFD323025A8506018ABF9D4DBAA746D61BF1CFB5C297D10\"\n" +
+ "}";
+
+ assertCanSerializeAndDeserialize(bridge, json);
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/XChainOwnedClaimIdObjectTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/XChainOwnedClaimIdObjectTest.java
new file mode 100644
index 000000000..6f3578aaf
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/XChainOwnedClaimIdObjectTest.java
@@ -0,0 +1,122 @@
+package org.xrpl.xrpl4j.model.ledger;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.crypto.keys.PublicKey;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.IssuedCurrencyAmount;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainClaimId;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+class XChainOwnedClaimIdObjectTest extends AbstractJsonTest {
+
+ @Test
+ void testJson() throws JSONException, JsonProcessingException {
+ XChainOwnedClaimIdObject object = XChainOwnedClaimIdObject.builder()
+ .account(Address.of("rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi"))
+ .otherChainSource(Address.of("r9oXrvBX5aDoyMGkoYvzazxDhYoWFUjz8p"))
+ .ownerNode("0")
+ .previousTransactionId(Hash256.of("1CFD80E9CF232B8EED62A52857DE97438D12230C06496932A81DEFA6E66070A6"))
+ .previousTransactionLedgerSequence(UnsignedInteger.valueOf(58673))
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .xChainBridge(
+ XChainBridge.builder()
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .lockingChainDoor(Address.of("rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4"))
+ .lockingChainIssue(Issue.XRP)
+ .build()
+ )
+ .addXChainClaimAttestations(
+ XChainClaimAttestation.of(
+ XChainClaimProofSig.builder()
+ .amount(XrpCurrencyAmount.ofDrops(1000000))
+ .attestationRewardAccount(Address.of("rfgjrgEJGDxfUY2U8VEDs7BnB1jiH3ofu6"))
+ .attestationSignerAccount(Address.of("rfsxNxZ6xB1nTPhTMwQajNnkCxWG8B714n"))
+ .destination(Address.of("rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi"))
+ .publicKey(
+ PublicKey.fromBase16EncodedPublicKey("025CA526EF20567A50FEC504589F949E0E3401C13EF76DD5FD1CC2850FA485BD7B")
+ )
+ .wasLockingChainSend(true)
+ .build()
+ ),
+ XChainClaimAttestation.of(
+ XChainClaimProofSig.builder()
+ .amount(
+ IssuedCurrencyAmount.builder()
+ .value("1")
+ .issuer(Address.of("rESSoiapL4EmPZTos6ks9FDZ6pbf261b3g"))
+ .currency("USD")
+ .build()
+ )
+ .attestationRewardAccount(Address.of("rUUL1tP523M8KimERqVS7sxb1tLLmpndyv"))
+ .attestationSignerAccount(Address.of("rEg5sHxZVTNwRL3BAdMwJatkmWDzHMmzDF"))
+ .publicKey(
+ PublicKey.fromBase16EncodedPublicKey("03D40434A6843638681E2F215310EBC4131AFB12EA85985DA073183B732525F7C9")
+ )
+ .wasLockingChainSend(false)
+ .build()
+ )
+ )
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.valueOf("b5", 16)))
+ .index(Hash256.of("20B136D7BF6D2E3D610E28E3E6BE09F5C8F4F0241BBF6E2D072AE1BACB1388F5"))
+ .build();
+
+ String json = "\n" +
+ "{\n" +
+ " \"Account\": \"rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi\",\n" +
+ " \"Flags\": 0,\n" +
+ " \"OtherChainSource\": \"r9oXrvBX5aDoyMGkoYvzazxDhYoWFUjz8p\",\n" +
+ " \"OwnerNode\": \"0\",\n" +
+ " \"PreviousTxnID\": \"1CFD80E9CF232B8EED62A52857DE97438D12230C06496932A81DEFA6E66070A6\",\n" +
+ " \"PreviousTxnLgrSeq\": 58673,\n" +
+ " \"SignatureReward\": \"100\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"XChainClaimAttestations\": [\n" +
+ " {\n" +
+ " \"XChainClaimProofSig\": {\n" +
+ " \"Amount\": \"1000000\",\n" +
+ " \"AttestationRewardAccount\": \"rfgjrgEJGDxfUY2U8VEDs7BnB1jiH3ofu6\",\n" +
+ " \"AttestationSignerAccount\": \"rfsxNxZ6xB1nTPhTMwQajNnkCxWG8B714n\",\n" +
+ " \"Destination\": \"rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi\",\n" +
+ " \"PublicKey\": \"025CA526EF20567A50FEC504589F949E0E3401C13EF76DD5FD1CC2850FA485BD7B\",\n" +
+ " \"WasLockingChainSend\": 1\n" +
+ " }\n" +
+ " },\n" +
+ " {\n" +
+ " \"XChainClaimProofSig\": {\n" +
+ " \"Amount\": {\n" +
+ " \"currency\": \"USD\",\n" +
+ " \"issuer\": \"rESSoiapL4EmPZTos6ks9FDZ6pbf261b3g\",\n" +
+ " \"value\": \"1\"\n" +
+ " },\n" +
+ " \"AttestationRewardAccount\": \"rUUL1tP523M8KimERqVS7sxb1tLLmpndyv\",\n" +
+ " \"AttestationSignerAccount\": \"rEg5sHxZVTNwRL3BAdMwJatkmWDzHMmzDF\",\n" +
+ " \"PublicKey\": \"03D40434A6843638681E2F215310EBC4131AFB12EA85985DA073183B732525F7C9\",\n" +
+ " \"WasLockingChainSend\": 0\n" +
+ " }\n" +
+ " }\n" +
+ " ],\n" +
+ " \"XChainClaimID\": \"b5\",\n" +
+ " \"LedgerEntryType\": \"XChainOwnedClaimID\",\n" +
+ " \"index\": \"20B136D7BF6D2E3D610E28E3E6BE09F5C8F4F0241BBF6E2D072AE1BACB1388F5\"\n" +
+ "}";
+
+ assertCanSerializeAndDeserialize(object, json);
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/XChainOwnedCreateAccountClaimIdObjectTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/XChainOwnedCreateAccountClaimIdObjectTest.java
new file mode 100644
index 000000000..032e8a74e
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/XChainOwnedCreateAccountClaimIdObjectTest.java
@@ -0,0 +1,123 @@
+package org.xrpl.xrpl4j.model.ledger;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.crypto.keys.PublicKey;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.IssuedCurrencyAmount;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainCount;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+class XChainOwnedCreateAccountClaimIdObjectTest extends AbstractJsonTest {
+
+ @Test
+ void testJson() throws JSONException, JsonProcessingException {
+ XChainOwnedCreateAccountClaimIdObject object = XChainOwnedCreateAccountClaimIdObject.builder()
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .ownerNode("0")
+ .previousTransactionId(Hash256.of("D6451F989A89E58C5E52C081D5C2DB34AE73035588968A6166151113A3B09E9A"))
+ .previousTransactionLedgerSequence(UnsignedInteger.valueOf(751272))
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.valueOf("2cf", 16)))
+ .xChainBridge(
+ XChainBridge.builder()
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .lockingChainDoor(Address.of("rnQAXXWoFNN6PEqwqsdTngCtFPCrmfuqFJ"))
+ .lockingChainIssue(Issue.XRP)
+ .build()
+ )
+ .addXChainCreateAccountAttestations(
+ XChainCreateAccountAttestation.of(
+ XChainCreateAccountProofSig.builder()
+ .amount(XrpCurrencyAmount.ofDrops(20000000))
+ .attestationRewardAccount(Address.of("rDUQ7WUgMZ6V75v3CFb1tqm1XPizmkWtTm"))
+ .attestationSignerAccount(Address.of("rUNdUjNcQde1Ye3823hn4RWjBYJEZYye3x"))
+ .destination(Address.of("rESSoiapL4EmPZTos6ks9FDZ6pbf261b3g"))
+ .publicKey(
+ PublicKey.fromBase16EncodedPublicKey("0300C9F746EF04811BB5529F7E58ACECA6DC5CFD5FDFB42C55C8630FC981D37A4E")
+ )
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .wasLockingChainSend(true)
+ .build()
+ ),
+ XChainCreateAccountAttestation.of(
+ XChainCreateAccountProofSig.builder()
+ .amount(
+ IssuedCurrencyAmount.builder()
+ .value("1")
+ .issuer(Address.of("rESSoiapL4EmPZTos6ks9FDZ6pbf261b3g"))
+ .currency("USD")
+ .build()
+ )
+ .attestationRewardAccount(Address.of("rLsS3B2m23Ms4oydi1bzNEp4R4EVxTFMrU"))
+ .attestationSignerAccount(Address.of("rJMQeMMRjsKmSwJ4ewMhVMVq3mbxTBwT3a"))
+ .destination(Address.of("rESSoiapL4EmPZTos6ks9FDZ6pbf261b3g"))
+ .publicKey(
+ PublicKey.fromBase16EncodedPublicKey("02C39C1AD5DBE3702D7D6A4A115618F5A0105EA394A0BD52FFA0C4787C3CB626CD")
+ )
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .wasLockingChainSend(false)
+ .build()
+ )
+ )
+ .index(Hash256.of("36AF95B8F602D97D3028968FAACEB5343435694990F1A0892BBB81DDCC033141"))
+ .build();
+
+ String json = "{\n" +
+ " \"Account\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"Flags\": 0,\n" +
+ " \"OwnerNode\": \"0\",\n" +
+ " \"PreviousTxnID\": \"D6451F989A89E58C5E52C081D5C2DB34AE73035588968A6166151113A3B09E9A\",\n" +
+ " \"PreviousTxnLgrSeq\": 751272,\n" +
+ " \"XChainAccountCreateCount\": \"2cf\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"LockingChainDoor\": \"rnQAXXWoFNN6PEqwqsdTngCtFPCrmfuqFJ\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"XChainCreateAccountAttestations\": [\n" +
+ " {\n" +
+ " \"XChainCreateAccountProofSig\": {\n" +
+ " \"Amount\": \"20000000\",\n" +
+ " \"AttestationRewardAccount\": \"rDUQ7WUgMZ6V75v3CFb1tqm1XPizmkWtTm\",\n" +
+ " \"AttestationSignerAccount\": \"rUNdUjNcQde1Ye3823hn4RWjBYJEZYye3x\",\n" +
+ " \"Destination\": \"rESSoiapL4EmPZTos6ks9FDZ6pbf261b3g\",\n" +
+ " \"PublicKey\": \"0300C9F746EF04811BB5529F7E58ACECA6DC5CFD5FDFB42C55C8630FC981D37A4E\",\n" +
+ " \"SignatureReward\": \"100\",\n" +
+ " \"WasLockingChainSend\": 1\n" +
+ " }\n" +
+ " },\n" +
+ " {\n" +
+ " \"XChainCreateAccountProofSig\": {\n" +
+ " \"Amount\": {\n" +
+ " \"currency\": \"USD\"," +
+ " \"issuer\": \"rESSoiapL4EmPZTos6ks9FDZ6pbf261b3g\"," +
+ " \"value\": \"1\"" +
+ " },\n" +
+ " \"AttestationRewardAccount\": \"rLsS3B2m23Ms4oydi1bzNEp4R4EVxTFMrU\",\n" +
+ " \"AttestationSignerAccount\": \"rJMQeMMRjsKmSwJ4ewMhVMVq3mbxTBwT3a\",\n" +
+ " \"Destination\": \"rESSoiapL4EmPZTos6ks9FDZ6pbf261b3g\",\n" +
+ " \"PublicKey\": \"02C39C1AD5DBE3702D7D6A4A115618F5A0105EA394A0BD52FFA0C4787C3CB626CD\",\n" +
+ " \"SignatureReward\": \"100\",\n" +
+ " \"WasLockingChainSend\": 0\n" +
+ " }\n" +
+ " }\n" +
+ " ]," +
+ " \"LedgerEntryType\": \"XChainOwnedCreateAccountClaimID\",\n" +
+ " \"index\": \"36AF95B8F602D97D3028968FAACEB5343435694990F1A0892BBB81DDCC033141\"\n" +
+ "}";
+
+ assertCanSerializeAndDeserialize(object, json);
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/TransactionMetadataTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/TransactionMetadataTest.java
index 1719a471a..7ae044486 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/TransactionMetadataTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/TransactionMetadataTest.java
@@ -705,7 +705,7 @@ private void deserializeFixtures(String fileName) throws IOException {
assertThat(CreatedNode.class).isAssignableFrom(transactionMetadata.affectedNodes().get(i).getClass());
if (node.getValue().get("NewFields") != null) {
MetaLedgerObject newFields = ((CreatedNode>) transactionMetadata.affectedNodes().get(i)).newFields();
- assertThat(determineLedgerObjectType(node.getValue().get("LedgerEntryType").asText()))
+ assertThat(MetaLedgerEntryType.of(node.getValue().get("LedgerEntryType").asText()).ledgerObjectType())
.isAssignableFrom(newFields.getClass());
}
} else if (node.getKey().equals("ModifiedNode")) {
@@ -714,14 +714,14 @@ private void deserializeFixtures(String fileName) throws IOException {
Optional> previousFields = ((ModifiedNode>) transactionMetadata.affectedNodes().get(i))
.previousFields();
assertThat(previousFields).isPresent();
- assertThat(determineLedgerObjectType(node.getValue().get("LedgerEntryType").asText()))
+ assertThat(MetaLedgerEntryType.of(node.getValue().get("LedgerEntryType").asText()).ledgerObjectType())
.isAssignableFrom(previousFields.get().getClass());
}
if (node.getValue().get("FinalFields") != null) {
Optional> finalFields = ((ModifiedNode>) transactionMetadata.affectedNodes().get(i)).finalFields();
assertThat(finalFields).isPresent();
- assertThat(determineLedgerObjectType(node.getValue().get("LedgerEntryType").asText()))
+ assertThat(MetaLedgerEntryType.of(node.getValue().get("LedgerEntryType").asText()).ledgerObjectType())
.isAssignableFrom(finalFields.get().getClass());
}
} else if (node.getKey().equals("DeletedNode")) {
@@ -729,7 +729,7 @@ private void deserializeFixtures(String fileName) throws IOException {
if (node.getValue().get("FinalFields") != null) {
MetaLedgerObject finalFields = ((DeletedNode>) transactionMetadata.affectedNodes().get(i))
.finalFields();
- assertThat(determineLedgerObjectType(node.getValue().get("LedgerEntryType").asText()))
+ assertThat(MetaLedgerEntryType.of(node.getValue().get("LedgerEntryType").asText()).ledgerObjectType())
.isAssignableFrom(finalFields.getClass());
}
}
@@ -780,35 +780,4 @@ private File newFile(File destinationDir, ZipEntry zipEntry) throws IOException
return destFile;
}
-
- private Class extends MetaLedgerObject> determineLedgerObjectType(String ledgerEntryType) {
- switch (ledgerEntryType) {
- case "AccountRoot":
- return MetaAccountRootObject.class;
- case "Check":
- return MetaCheckObject.class;
- case "DepositPreauth":
- return MetaDepositPreAuthObject.class;
- case "Escrow":
- return MetaEscrowObject.class;
- case "NFTokenOffer":
- return MetaNfTokenOfferObject.class;
- case "Offer":
- return MetaOfferObject.class;
- case "PayChannel":
- return MetaPayChannelObject.class;
- case "RippleState":
- return MetaRippleStateObject.class;
- case "SignerList":
- return MetaSignerListObject.class;
- case "Ticket":
- return MetaTicketObject.class;
- case "NFTokenPage":
- return MetaNfTokenPageObject.class;
- case "AMM":
- return MetaAmmObject.class;
- default:
- return MetaUnknownObject.class;
- }
- }
}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/TransactionTypeTests.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/TransactionTypeTests.java
index 16e836144..77beee833 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/TransactionTypeTests.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/TransactionTypeTests.java
@@ -98,5 +98,21 @@ public void testTxTypeCapitalization() {
assertThat(TransactionType.TRUST_SET.value()).isEqualTo("TrustSet");
assertThat(TransactionType.TICKET_CREATE.value()).isEqualTo("TicketCreate");
assertThat(TransactionType.UNL_MODIFY.value()).isEqualTo("UNLModify");
+ assertThat(TransactionType.CLAWBACK.value()).isEqualTo("Clawback");
+ assertThat(TransactionType.AMM_BID.value()).isEqualTo("AMMBid");
+ assertThat(TransactionType.AMM_CREATE.value()).isEqualTo("AMMCreate");
+ assertThat(TransactionType.AMM_DEPOSIT.value()).isEqualTo("AMMDeposit");
+ assertThat(TransactionType.AMM_VOTE.value()).isEqualTo("AMMVote");
+ assertThat(TransactionType.AMM_WITHDRAW.value()).isEqualTo("AMMWithdraw");
+ assertThat(TransactionType.AMM_DELETE.value()).isEqualTo("AMMDelete");
+ assertThat(TransactionType.XCHAIN_ACCOUNT_CREATE_COMMIT.value()).isEqualTo("XChainAccountCreateCommit");
+ assertThat(TransactionType.XCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION.value())
+ .isEqualTo("XChainAddAccountCreateAttestation");
+ assertThat(TransactionType.XCHAIN_ADD_CLAIM_ATTESTATION.value()).isEqualTo("XChainAddClaimAttestation");
+ assertThat(TransactionType.XCHAIN_CLAIM.value()).isEqualTo("XChainClaim");
+ assertThat(TransactionType.XCHAIN_COMMIT.value()).isEqualTo("XChainCommit");
+ assertThat(TransactionType.XCHAIN_CREATE_BRIDGE.value()).isEqualTo("XChainCreateBridge");
+ assertThat(TransactionType.XCHAIN_CREATE_CLAIM_ID.value()).isEqualTo("XChainCreateClaimID");
+ assertThat(TransactionType.XCHAIN_MODIFY_BRIDGE.value()).isEqualTo("XChainModifyBridge");
}
}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainAccountCreateCommitTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainAccountCreateCommitTest.java
new file mode 100644
index 000000000..9996af22a
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainAccountCreateCommitTest.java
@@ -0,0 +1,216 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+import org.xrpl.xrpl4j.model.ledger.Issue;
+
+class XChainAccountCreateCommitTest extends AbstractJsonTest {
+
+ @Test
+ void testJsonWithEmptyFlags() throws JSONException, JsonProcessingException {
+ XChainAccountCreateCommit commit = XChainAccountCreateCommit.builder()
+ .account(Address.of("rwEqJ2UaQHe7jihxGqmx6J4xdbGiiyMaGa"))
+ .fee(XrpCurrencyAmount.ofDrops(1))
+ .sequence(UnsignedInteger.ONE)
+ .destination(Address.of("rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo"))
+ .amount(XrpCurrencyAmount.ofDrops(20000000))
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .signingPublicKey(ED_PUBLIC_KEY)
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(
+ Issue.builder()
+ .currency("TST")
+ .issuer(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .build()
+ )
+ .build()
+ )
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rwEqJ2UaQHe7jihxGqmx6J4xdbGiiyMaGa\",\n" +
+ " \"Fee\": \"1\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"Destination\": \"rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo\",\n" +
+ " \"TransactionType\": \"XChainAccountCreateCommit\",\n" +
+ " \"Amount\": \"20000000\",\n" +
+ " \"SignatureReward\": \"100\",\n" +
+ " \"SigningPubKey\": \"%s\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"TST\",\n" +
+ " \"issuer\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\"\n" +
+ " }\n" +
+ " }\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(commit, json);
+ }
+
+ @Test
+ void testJsonWithUnsetFlags() throws JSONException, JsonProcessingException {
+ XChainAccountCreateCommit commit = XChainAccountCreateCommit.builder()
+ .account(Address.of("rwEqJ2UaQHe7jihxGqmx6J4xdbGiiyMaGa"))
+ .fee(XrpCurrencyAmount.ofDrops(1))
+ .sequence(UnsignedInteger.ONE)
+ .destination(Address.of("rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo"))
+ .amount(XrpCurrencyAmount.ofDrops(20000000))
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .signingPublicKey(ED_PUBLIC_KEY)
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(
+ Issue.builder()
+ .currency("TST")
+ .issuer(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .build()
+ )
+ .build()
+ )
+ .flags(TransactionFlags.UNSET)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rwEqJ2UaQHe7jihxGqmx6J4xdbGiiyMaGa\",\n" +
+ " \"Fee\": \"1\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"Destination\": \"rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo\",\n" +
+ " \"TransactionType\": \"XChainAccountCreateCommit\",\n" +
+ " \"Amount\": \"20000000\",\n" +
+ " \"SignatureReward\": \"100\",\n" +
+ " \"SigningPubKey\": \"%s\",\n" +
+ " \"Flags\": 0,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"TST\",\n" +
+ " \"issuer\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\"\n" +
+ " }\n" +
+ " }\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(commit, json);
+ }
+
+ @Test
+ void testJsonWithFullyCanonicalSigFlags() throws JSONException, JsonProcessingException {
+ XChainAccountCreateCommit commit = XChainAccountCreateCommit.builder()
+ .account(Address.of("rwEqJ2UaQHe7jihxGqmx6J4xdbGiiyMaGa"))
+ .fee(XrpCurrencyAmount.ofDrops(1))
+ .sequence(UnsignedInteger.ONE)
+ .destination(Address.of("rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo"))
+ .amount(XrpCurrencyAmount.ofDrops(20000000))
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .signingPublicKey(ED_PUBLIC_KEY)
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(
+ Issue.builder()
+ .currency("TST")
+ .issuer(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .build()
+ )
+ .build()
+ )
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rwEqJ2UaQHe7jihxGqmx6J4xdbGiiyMaGa\",\n" +
+ " \"Fee\": \"1\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"Destination\": \"rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo\",\n" +
+ " \"TransactionType\": \"XChainAccountCreateCommit\",\n" +
+ " \"Amount\": \"20000000\",\n" +
+ " \"SignatureReward\": \"100\",\n" +
+ " \"SigningPubKey\": \"%s\",\n" +
+ " \"Flags\": %s,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"TST\",\n" +
+ " \"issuer\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\"\n" +
+ " }\n" +
+ " }\n" +
+ "}", ED_PUBLIC_KEY.base16Value(), TransactionFlags.FULLY_CANONICAL_SIG);
+
+ assertCanSerializeAndDeserialize(commit, json);
+ }
+
+ @Test
+ void testJsonWithEmptySignatureReward() throws JSONException, JsonProcessingException {
+ XChainAccountCreateCommit commit = XChainAccountCreateCommit.builder()
+ .account(Address.of("rwEqJ2UaQHe7jihxGqmx6J4xdbGiiyMaGa"))
+ .fee(XrpCurrencyAmount.ofDrops(1))
+ .sequence(UnsignedInteger.ONE)
+ .destination(Address.of("rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo"))
+ .amount(XrpCurrencyAmount.ofDrops(20000000))
+ .signingPublicKey(ED_PUBLIC_KEY)
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(
+ Issue.builder()
+ .currency("TST")
+ .issuer(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .build()
+ )
+ .build()
+ )
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rwEqJ2UaQHe7jihxGqmx6J4xdbGiiyMaGa\",\n" +
+ " \"Fee\": \"1\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"Destination\": \"rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo\",\n" +
+ " \"TransactionType\": \"XChainAccountCreateCommit\",\n" +
+ " \"Amount\": \"20000000\",\n" +
+ " \"SigningPubKey\": \"%s\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"TST\",\n" +
+ " \"issuer\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\"\n" +
+ " }\n" +
+ " }\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(commit, json);
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainAddAccountCreateAttestationTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainAddAccountCreateAttestationTest.java
new file mode 100644
index 000000000..dbb05e850
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainAddAccountCreateAttestationTest.java
@@ -0,0 +1,233 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.crypto.keys.PublicKey;
+import org.xrpl.xrpl4j.crypto.signing.Signature;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+import org.xrpl.xrpl4j.model.ledger.Issue;
+
+class XChainAddAccountCreateAttestationTest extends AbstractJsonTest {
+
+ @Test
+ void testJsonWithEmptyFlags() throws JSONException, JsonProcessingException {
+ XChainAddAccountCreateAttestation transaction = baseBuilder().build();
+ String json = String.format("{\n" +
+ " \"Account\": \"rDr5okqGKmMpn44Bbhe5WAfDQx8e9XquEv\",\n" +
+ " \"TransactionType\": \"XChainAddAccountCreateAttestation\",\n" +
+ " \"OtherChainSource\": \"rUzB7yg1LcFa7m3q1hfrjr5w53vcWzNh3U\",\n" +
+ " \"Destination\": \"rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd\",\n" +
+ " \"Amount\": \"2000000000\",\n" +
+ " \"PublicKey\": \"EDF7C3F9C80C102AF6D241752B37356E91ED454F26A35C567CF6F8477960F66614\",\n" +
+ " \"Signature\": \"F95675BA8FDA21030DE1B687937A79E8491CE51832D6BEEBC071484FA5AF5B8A0E9AFF11A4AA46F09EC" +
+ "FFB04C6A8DAE8284AF3ED8128C7D0046D842448478500\",\n" +
+ " \"WasLockingChainSend\": 1,\n" +
+ " \"AttestationRewardAccount\": \"rpFp36UHW6FpEcZjZqq5jSJWY6UCj3k4Es\",\n" +
+ " \"AttestationSignerAccount\": \"rpWLegmW9WrFBzHUj7brhQNZzrxgLj9oxw\",\n" +
+ " \"XChainAccountCreateCount\": \"2\",\n" +
+ " \"SignatureReward\": \"204\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"20\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ @Test
+ void testJsonWithUnsetFlags() throws JSONException, JsonProcessingException {
+ XChainAddAccountCreateAttestation transaction = baseBuilder()
+ .flags(TransactionFlags.UNSET)
+ .build();
+ String json = String.format("{\n" +
+ " \"Account\": \"rDr5okqGKmMpn44Bbhe5WAfDQx8e9XquEv\",\n" +
+ " \"TransactionType\": \"XChainAddAccountCreateAttestation\",\n" +
+ " \"OtherChainSource\": \"rUzB7yg1LcFa7m3q1hfrjr5w53vcWzNh3U\",\n" +
+ " \"Destination\": \"rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd\",\n" +
+ " \"Amount\": \"2000000000\",\n" +
+ " \"PublicKey\": \"EDF7C3F9C80C102AF6D241752B37356E91ED454F26A35C567CF6F8477960F66614\",\n" +
+ " \"Signature\": \"F95675BA8FDA21030DE1B687937A79E8491CE51832D6BEEBC071484FA5AF5B8A0E9AFF11A4AA46" +
+ "F09ECFFB04C6A8DAE8284AF3ED8128C7D0046D842448478500\",\n" +
+ " \"WasLockingChainSend\": 1,\n" +
+ " \"AttestationRewardAccount\": \"rpFp36UHW6FpEcZjZqq5jSJWY6UCj3k4Es\",\n" +
+ " \"AttestationSignerAccount\": \"rpWLegmW9WrFBzHUj7brhQNZzrxgLj9oxw\",\n" +
+ " \"XChainAccountCreateCount\": \"2\",\n" +
+ " \"SignatureReward\": \"204\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"Flags\": 0,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"20\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ @Test
+ void testJsonWithFullyCanonicalSig() throws JSONException, JsonProcessingException {
+ XChainAddAccountCreateAttestation transaction = baseBuilder()
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .build();
+ String json = String.format("{\n" +
+ " \"Account\": \"rDr5okqGKmMpn44Bbhe5WAfDQx8e9XquEv\",\n" +
+ " \"TransactionType\": \"XChainAddAccountCreateAttestation\",\n" +
+ " \"OtherChainSource\": \"rUzB7yg1LcFa7m3q1hfrjr5w53vcWzNh3U\",\n" +
+ " \"Destination\": \"rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd\",\n" +
+ " \"Amount\": \"2000000000\",\n" +
+ " \"PublicKey\": \"EDF7C3F9C80C102AF6D241752B37356E91ED454F26A35C567CF6F8477960F66614\",\n" +
+ " \"Signature\": \"F95675BA8FDA21030DE1B687937A79E8491CE51832D6BEEBC071484FA5AF5B8A0E9AFF11A4AA46F09ECFF" +
+ "B04C6A8DAE8284AF3ED8128C7D0046D842448478500\",\n" +
+ " \"WasLockingChainSend\": 1,\n" +
+ " \"AttestationRewardAccount\": \"rpFp36UHW6FpEcZjZqq5jSJWY6UCj3k4Es\",\n" +
+ " \"AttestationSignerAccount\": \"rpWLegmW9WrFBzHUj7brhQNZzrxgLj9oxw\",\n" +
+ " \"XChainAccountCreateCount\": \"2\",\n" +
+ " \"SignatureReward\": \"204\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"Flags\": %s,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"20\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value(), TransactionFlags.FULLY_CANONICAL_SIG);
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ @Test
+ void testJsonWithWasLockingChainSendTrue() throws JSONException, JsonProcessingException {
+ XChainAddAccountCreateAttestation transaction = baseBuilder()
+ .wasLockingChainSend(true)
+ .build();
+ String json = String.format("{\n" +
+ " \"Account\": \"rDr5okqGKmMpn44Bbhe5WAfDQx8e9XquEv\",\n" +
+ " \"TransactionType\": \"XChainAddAccountCreateAttestation\",\n" +
+ " \"OtherChainSource\": \"rUzB7yg1LcFa7m3q1hfrjr5w53vcWzNh3U\",\n" +
+ " \"Destination\": \"rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd\",\n" +
+ " \"Amount\": \"2000000000\",\n" +
+ " \"PublicKey\": \"EDF7C3F9C80C102AF6D241752B37356E91ED454F26A35C567CF6F8477960F66614\",\n" +
+ " \"Signature\": \"F95675BA8FDA21030DE1B687937A79E8491CE51832D6BEEBC071484FA5AF5B8A0E9AFF11A4AA46F09E" +
+ "CFFB04C6A8DAE8284AF3ED8128C7D0046D842448478500\",\n" +
+ " \"WasLockingChainSend\": 1,\n" +
+ " \"AttestationRewardAccount\": \"rpFp36UHW6FpEcZjZqq5jSJWY6UCj3k4Es\",\n" +
+ " \"AttestationSignerAccount\": \"rpWLegmW9WrFBzHUj7brhQNZzrxgLj9oxw\",\n" +
+ " \"XChainAccountCreateCount\": \"2\",\n" +
+ " \"SignatureReward\": \"204\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"20\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ @Test
+ void testJsonWithWasLockingChainSendFalse() throws JSONException, JsonProcessingException {
+ XChainAddAccountCreateAttestation transaction = baseBuilder()
+ .wasLockingChainSend(false)
+ .build();
+ String json = String.format("{\n" +
+ " \"Account\": \"rDr5okqGKmMpn44Bbhe5WAfDQx8e9XquEv\",\n" +
+ " \"TransactionType\": \"XChainAddAccountCreateAttestation\",\n" +
+ " \"OtherChainSource\": \"rUzB7yg1LcFa7m3q1hfrjr5w53vcWzNh3U\",\n" +
+ " \"Destination\": \"rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd\",\n" +
+ " \"Amount\": \"2000000000\",\n" +
+ " \"PublicKey\": \"EDF7C3F9C80C102AF6D241752B37356E91ED454F26A35C567CF6F8477960F66614\",\n" +
+ " \"Signature\": \"F95675BA8FDA21030DE1B687937A79E8491CE51832D6BEEBC071484FA5AF5B8A0E9AFF11A4AA46F0" +
+ "9ECFFB04C6A8DAE8284AF3ED8128C7D0046D842448478500\",\n" +
+ " \"WasLockingChainSend\": 0,\n" +
+ " \"AttestationRewardAccount\": \"rpFp36UHW6FpEcZjZqq5jSJWY6UCj3k4Es\",\n" +
+ " \"AttestationSignerAccount\": \"rpWLegmW9WrFBzHUj7brhQNZzrxgLj9oxw\",\n" +
+ " \"XChainAccountCreateCount\": \"2\",\n" +
+ " \"SignatureReward\": \"204\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"20\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ private ImmutableXChainAddAccountCreateAttestation.Builder baseBuilder() {
+ return XChainAddAccountCreateAttestation.builder()
+ .account(Address.of("rDr5okqGKmMpn44Bbhe5WAfDQx8e9XquEv"))
+ .otherChainSource(Address.of("rUzB7yg1LcFa7m3q1hfrjr5w53vcWzNh3U"))
+ .destination(Address.of("rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd"))
+ .amount(XrpCurrencyAmount.ofDrops(2000000000))
+ .publicKey(
+ PublicKey.fromBase16EncodedPublicKey("EDF7C3F9C80C102AF6D241752B37356E91ED454F26A35C567CF6F8477960F66614")
+ )
+ .signature(
+ Signature.fromBase16("F95675BA8FDA21030DE1B687937A79E8491CE51832D6BEEBC071484FA5AF5B8A0E" +
+ "9AFF11A4AA46F09ECFFB04C6A8DAE8284AF3ED8128C7D0046D842448478500")
+ )
+ .wasLockingChainSend(true)
+ .attestationRewardAccount(Address.of("rpFp36UHW6FpEcZjZqq5jSJWY6UCj3k4Es"))
+ .attestationSignerAccount(Address.of("rpWLegmW9WrFBzHUj7brhQNZzrxgLj9oxw"))
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.valueOf(2)))
+ .signatureReward(XrpCurrencyAmount.ofDrops(204))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .fee(XrpCurrencyAmount.ofDrops(20))
+ .sequence(UnsignedInteger.ONE)
+ .signingPublicKey(ED_PUBLIC_KEY);
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainAddClaimAttestationTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainAddClaimAttestationTest.java
new file mode 100644
index 000000000..d1c158446
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainAddClaimAttestationTest.java
@@ -0,0 +1,239 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.crypto.keys.PublicKey;
+import org.xrpl.xrpl4j.crypto.signing.Signature;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+import org.xrpl.xrpl4j.model.ledger.Issue;
+
+import java.util.Optional;
+
+class XChainAddClaimAttestationTest extends AbstractJsonTest {
+
+ @Test
+ void testJsonWithFalseWasLockingChainSend() throws JSONException, JsonProcessingException {
+ XChainAddClaimAttestation attestation = baseBuilder()
+ .wasLockingChainSend(false)
+ .build();
+
+ String json = "{\n" +
+ " \"Account\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"Amount\": \"10000000\",\n" +
+ " \"AttestationRewardAccount\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"AttestationSignerAccount\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"Destination\": \"rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi\",\n" +
+ " \"Fee\": \"20\",\n" +
+ " \"LastLedgerSequence\": 19,\n" +
+ " \"OtherChainSource\": \"raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym\",\n" +
+ " \"PublicKey\": \"ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E1136\",\n" +
+ " \"Sequence\": 9,\n" +
+ " \"Signature\": \"7C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44528FE99AA5" +
+ "0E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C\",\n" +
+ " \"SigningPubKey\": \"ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C\",\n" +
+ " \"TransactionType\": \"XChainAddClaimAttestation\",\n" +
+ " \"WasLockingChainSend\": 0,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"LockingChainDoor\": \"rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"XChainClaimID\": \"1\"\n" +
+ " }";
+
+ assertCanSerializeAndDeserialize(attestation, json);
+ }
+
+ @Test
+ void testJsonWithEmptyDestination() throws JSONException, JsonProcessingException {
+ XChainAddClaimAttestation attestation = baseBuilder()
+ .destination(Optional.empty())
+ .build();
+
+ String json = "{\n" +
+ " \"Account\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"Amount\": \"10000000\",\n" +
+ " \"AttestationRewardAccount\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"AttestationSignerAccount\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"Fee\": \"20\",\n" +
+ " \"LastLedgerSequence\": 19,\n" +
+ " \"OtherChainSource\": \"raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym\",\n" +
+ " \"PublicKey\": \"ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E1136\",\n" +
+ " \"Sequence\": 9,\n" +
+ " \"Signature\": \"7C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44528FE99AA50E716" +
+ "60A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C\",\n" +
+ " \"SigningPubKey\": \"ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C\",\n" +
+ " \"TransactionType\": \"XChainAddClaimAttestation\",\n" +
+ " \"WasLockingChainSend\": 1,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"LockingChainDoor\": \"rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"XChainClaimID\": \"1\"\n" +
+ " }";
+
+ assertCanSerializeAndDeserialize(attestation, json);
+ }
+
+ @Test
+ void testJsonWithEmptyFlags() throws JSONException, JsonProcessingException {
+ XChainAddClaimAttestation attestation = baseBuilder().build();
+
+ String json = "{\n" +
+ " \"Account\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"Amount\": \"10000000\",\n" +
+ " \"AttestationRewardAccount\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"AttestationSignerAccount\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"Destination\": \"rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi\",\n" +
+ " \"Fee\": \"20\",\n" +
+ " \"LastLedgerSequence\": 19,\n" +
+ " \"OtherChainSource\": \"raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym\",\n" +
+ " \"PublicKey\": \"ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E1136\",\n" +
+ " \"Sequence\": 9,\n" +
+ " \"Signature\": \"7C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44528FE99AA50E7166" +
+ "0A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C\",\n" +
+ " \"SigningPubKey\": \"ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C\",\n" +
+ " \"TransactionType\": \"XChainAddClaimAttestation\",\n" +
+ " \"WasLockingChainSend\": 1,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"LockingChainDoor\": \"rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"XChainClaimID\": \"1\"\n" +
+ " }";
+
+ assertCanSerializeAndDeserialize(attestation, json);
+ }
+
+ @Test
+ void testJsonWithUnsetFlags() throws JSONException, JsonProcessingException {
+ XChainAddClaimAttestation attestation = baseBuilder()
+ .flags(TransactionFlags.UNSET)
+ .build();
+
+ String json = "{\n" +
+ " \"Account\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"Amount\": \"10000000\",\n" +
+ " \"AttestationRewardAccount\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"AttestationSignerAccount\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"Destination\": \"rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi\",\n" +
+ " \"Fee\": \"20\",\n" +
+ " \"Flags\": 0,\n" +
+ " \"LastLedgerSequence\": 19,\n" +
+ " \"OtherChainSource\": \"raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym\",\n" +
+ " \"PublicKey\": \"ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E1136\",\n" +
+ " \"Sequence\": 9,\n" +
+ " \"Signature\": \"7C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44528FE99AA5" +
+ "0E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C\",\n" +
+ " \"SigningPubKey\": \"ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C\",\n" +
+ " \"TransactionType\": \"XChainAddClaimAttestation\",\n" +
+ " \"WasLockingChainSend\": 1,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"LockingChainDoor\": \"rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"XChainClaimID\": \"1\"\n" +
+ " }";
+
+ assertCanSerializeAndDeserialize(attestation, json);
+ }
+
+ @Test
+ void testJsonWithFullyCanonicalSigFlags() throws JSONException, JsonProcessingException {
+ XChainAddClaimAttestation attestation = baseBuilder()
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"Amount\": \"10000000\",\n" +
+ " \"AttestationRewardAccount\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"AttestationSignerAccount\": \"rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3\",\n" +
+ " \"Destination\": \"rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi\",\n" +
+ " \"Fee\": \"20\",\n" +
+ " \"Flags\": %s,\n" +
+ " \"LastLedgerSequence\": 19,\n" +
+ " \"OtherChainSource\": \"raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym\",\n" +
+ " \"PublicKey\": \"ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E1136\",\n" +
+ " \"Sequence\": 9,\n" +
+ " \"Signature\": \"7C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44528FE99A" +
+ "A50E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C\",\n" +
+ " \"SigningPubKey\": \"ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C\",\n" +
+ " \"TransactionType\": \"XChainAddClaimAttestation\",\n" +
+ " \"WasLockingChainSend\": 1,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"LockingChainDoor\": \"rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"XChainClaimID\": \"1\"\n" +
+ " }", TransactionFlags.FULLY_CANONICAL_SIG);
+
+ assertCanSerializeAndDeserialize(attestation, json);
+ }
+
+ private ImmutableXChainAddClaimAttestation.Builder baseBuilder() {
+ return XChainAddClaimAttestation.builder()
+ .account(Address.of("rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3"))
+ .amount(XrpCurrencyAmount.ofDrops(10000000))
+ .attestationRewardAccount(Address.of("rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3"))
+ .attestationSignerAccount(Address.of("rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3"))
+ .destination(Address.of("rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi"))
+ .fee(XrpCurrencyAmount.ofDrops(20))
+ .lastLedgerSequence(UnsignedInteger.valueOf(19))
+ .otherChainSource(Address.of("raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym"))
+ .sequence(UnsignedInteger.valueOf(9))
+ .publicKey(
+ PublicKey.fromBase16EncodedPublicKey("ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E1136")
+ )
+ .signature(
+ Signature.fromBase16("7C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44" +
+ "528FE99AA50E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C")
+ )
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C")
+ )
+ .wasLockingChainSend(true)
+ .xChainBridge(
+ XChainBridge.builder()
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .lockingChainDoor(Address.of("rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg"))
+ .lockingChainIssue(Issue.XRP)
+ .build()
+ )
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE));
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainClaimIdTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainClaimIdTest.java
new file mode 100644
index 000000000..afe177207
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainClaimIdTest.java
@@ -0,0 +1,76 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.assertj.core.api.Assertions;
+import org.immutables.value.Value;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.skyscreamer.jsonassert.JSONCompareMode;
+import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory;
+
+import java.math.BigDecimal;
+
+public class XChainClaimIdTest {
+
+ ObjectMapper objectMapper = ObjectMapperFactory.create();
+
+ @Test
+ void testToString() {
+ XChainClaimId claimId = XChainClaimId.of(UnsignedLong.ZERO);
+ assertThat(claimId.toString()).isEqualTo("0");
+
+ XChainClaimId claimIdMax = XChainClaimId.of(UnsignedLong.MAX_VALUE);
+ assertThat(claimIdMax.toString()).isEqualTo("18446744073709551615");
+ }
+
+ @Test
+ void testJson() throws JsonProcessingException, JSONException {
+ XChainClaimId claimId = XChainClaimId.of(UnsignedLong.valueOf(1000));
+ XChainClaimIdWrapper wrapper = XChainClaimIdWrapper.of(claimId);
+
+ String json = "{\"claimId\": \"3e8\"}";
+ assertSerializesAndDeserializes(wrapper, json);
+ }
+
+ @Test
+ void testMaxJson() throws JSONException, JsonProcessingException {
+ XChainClaimId claimId = XChainClaimId.of(UnsignedLong.MAX_VALUE);
+ XChainClaimIdWrapper wrapper = XChainClaimIdWrapper.of(claimId);
+
+ String json = "{\"claimId\": \"ffffffffffffffff\"}";
+ assertSerializesAndDeserializes(wrapper, json);
+ }
+
+ private void assertSerializesAndDeserializes(
+ XChainClaimIdWrapper wrapper,
+ String json
+ ) throws JsonProcessingException, JSONException {
+ String serialized = objectMapper.writeValueAsString(wrapper);
+ JSONAssert.assertEquals(json, serialized, JSONCompareMode.STRICT);
+ XChainClaimIdWrapper deserialized = objectMapper.readValue(
+ serialized, XChainClaimIdWrapper.class
+ );
+ Assertions.assertThat(deserialized).isEqualTo(wrapper);
+ }
+
+ @Value.Immutable
+ @JsonSerialize(as = ImmutableXChainClaimIdWrapper.class)
+ @JsonDeserialize(as = ImmutableXChainClaimIdWrapper.class)
+ interface XChainClaimIdWrapper {
+
+ static XChainClaimIdWrapper of(XChainClaimId claimId) {
+ return ImmutableXChainClaimIdWrapper.builder().claimId(claimId).build();
+ }
+
+ XChainClaimId claimId();
+
+ }
+}
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainClaimTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainClaimTest.java
new file mode 100644
index 000000000..4426f54dd
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainClaimTest.java
@@ -0,0 +1,155 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+import org.xrpl.xrpl4j.model.ledger.Issue;
+
+class XChainClaimTest extends AbstractJsonTest {
+
+ @Test
+ void testJsonWithDestinationTag() throws JSONException, JsonProcessingException {
+ XChainClaim attestation = baseBuilder()
+ .destinationTag(UnsignedInteger.ONE)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"Amount\": \"10000\",\n" +
+ " \"Fee\": \"12\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"TransactionType\": \"XChainClaim\",\n" +
+ " \"XChainClaimID\": \"13f\",\n" +
+ " \"Destination\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"DestinationTag\": 1,\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " }\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(attestation, json);
+ }
+
+ @Test
+ void testJsonWithEmptyFlags() throws JSONException, JsonProcessingException {
+ XChainClaim attestation = baseBuilder().build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"Amount\": \"10000\",\n" +
+ " \"Fee\": \"12\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"TransactionType\": \"XChainClaim\",\n" +
+ " \"XChainClaimID\": \"13f\",\n" +
+ " \"Destination\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " }\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(attestation, json);
+ }
+
+ @Test
+ void testJsonWithUnsetFlags() throws JSONException, JsonProcessingException {
+ XChainClaim attestation = baseBuilder()
+ .flags(TransactionFlags.UNSET)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"Amount\": \"10000\",\n" +
+ " \"Fee\": \"12\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"Flags\": 0,\n" +
+ " \"TransactionType\": \"XChainClaim\",\n" +
+ " \"XChainClaimID\": \"13f\",\n" +
+ " \"Destination\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " }\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(attestation, json);
+ }
+
+ @Test
+ void testJsonWithFullyCanonicalSigFlags() throws JSONException, JsonProcessingException {
+ XChainClaim attestation = baseBuilder()
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"Amount\": \"10000\",\n" +
+ " \"Fee\": \"12\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"Flags\": %s,\n" +
+ " \"TransactionType\": \"XChainClaim\",\n" +
+ " \"XChainClaimID\": \"13f\",\n" +
+ " \"Destination\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " }\n" +
+ "}", ED_PUBLIC_KEY.base16Value(), TransactionFlags.FULLY_CANONICAL_SIG);
+
+ assertCanSerializeAndDeserialize(attestation, json);
+ }
+
+ private ImmutableXChainClaim.Builder baseBuilder() {
+ return XChainClaim.builder()
+ .account(Address.of("rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw"))
+ .fee(XrpCurrencyAmount.ofDrops(12))
+ .sequence(UnsignedInteger.ONE)
+ .signingPublicKey(ED_PUBLIC_KEY)
+ .amount(XrpCurrencyAmount.ofDrops(10000))
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.valueOf(0x13F)))
+ .destination(Address.of("rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw"))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ );
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCommitTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCommitTest.java
new file mode 100644
index 000000000..270229447
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCommitTest.java
@@ -0,0 +1,159 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+import org.xrpl.xrpl4j.model.ledger.Issue;
+
+class XChainCommitTest extends AbstractJsonTest {
+
+ @Test
+ void testJsonWithIssuedCurrencyAmount() throws JSONException, JsonProcessingException {
+ XChainCommit commit = baseBuilder()
+ .amount(
+ IssuedCurrencyAmount.builder()
+ .currency("CNY")
+ .issuer(Address.of("r45dBj4S3VvMMYXxr9vHX4Z4Ma6ifPMCkK"))
+ .value("5000")
+ .build()
+ )
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo\",\n" +
+ " \"TransactionType\": \"XChainCommit\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Amount\": {" +
+ " \"currency\": \"CNY\",\n" +
+ " \"value\": \"5000\",\n" +
+ " \"issuer\": \"r45dBj4S3VvMMYXxr9vHX4Z4Ma6ifPMCkK\"\n" +
+ " },\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"XChainClaimID\": \"13f\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(commit, json);
+ }
+
+ @Test
+ void testJsonWithEmptyFlags() throws JSONException, JsonProcessingException {
+ XChainCommit commit = baseBuilder().build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo\",\n" +
+ " \"TransactionType\": \"XChainCommit\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Amount\": \"10000\",\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"XChainClaimID\": \"13f\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(commit, json);
+ }
+
+ @Test
+ void testJsonWithUnsetFlags() throws JSONException, JsonProcessingException {
+ XChainCommit commit = baseBuilder()
+ .flags(TransactionFlags.UNSET)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo\",\n" +
+ " \"TransactionType\": \"XChainCommit\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Amount\": \"10000\",\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"Flags\": 0,\n" +
+ " \"XChainClaimID\": \"13f\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(commit, json);
+ }
+
+ @Test
+ void testJsonWithFullyCanonicalSigFlags() throws JSONException, JsonProcessingException {
+ XChainCommit commit = baseBuilder()
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"Account\": \"rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo\",\n" +
+ " \"TransactionType\": \"XChainCommit\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Amount\": \"10000\",\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s,\n" +
+ " \"Flags\": %s,\n" +
+ " \"XChainClaimID\": \"13f\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value(), TransactionFlags.FULLY_CANONICAL_SIG);
+
+ assertCanSerializeAndDeserialize(commit, json);
+ }
+
+ private ImmutableXChainCommit.Builder baseBuilder() {
+ return XChainCommit.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(Address.of("rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo"))
+ .amount(XrpCurrencyAmount.ofDrops(10000))
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.valueOf(0x13f)))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .signingPublicKey(ED_PUBLIC_KEY);
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCountTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCountTest.java
new file mode 100644
index 000000000..dffade43f
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCountTest.java
@@ -0,0 +1,73 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.primitives.UnsignedLong;
+import org.assertj.core.api.Assertions;
+import org.immutables.value.Value;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.skyscreamer.jsonassert.JSONCompareMode;
+import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory;
+
+public class XChainCountTest {
+
+ ObjectMapper objectMapper = ObjectMapperFactory.create();
+
+ @Test
+ void testToString() {
+ XChainCount count = XChainCount.of(UnsignedLong.ZERO);
+ assertThat(count.toString()).isEqualTo("0");
+
+ XChainCount countMax = XChainCount.of(UnsignedLong.MAX_VALUE);
+ assertThat(countMax.toString()).isEqualTo("18446744073709551615");
+ }
+
+ @Test
+ void testJson() throws JsonProcessingException, JSONException {
+ XChainCount count = XChainCount.of(UnsignedLong.valueOf(1000));
+ XChainCountWrapper wrapper = XChainCountWrapper.of(count);
+
+ String json = "{\"count\": \"3e8\"}";
+ assertSerializesAndDeserializes(wrapper, json);
+ }
+
+ @Test
+ void testMaxJson() throws JSONException, JsonProcessingException {
+ XChainCount count = XChainCount.of(UnsignedLong.MAX_VALUE);
+ XChainCountWrapper wrapper = XChainCountWrapper.of(count);
+
+ String json = "{\"count\": \"ffffffffffffffff\"}";
+ assertSerializesAndDeserializes(wrapper, json);
+ }
+
+ private void assertSerializesAndDeserializes(
+ XChainCountWrapper wrapper,
+ String json
+ ) throws JsonProcessingException, JSONException {
+ String serialized = objectMapper.writeValueAsString(wrapper);
+ JSONAssert.assertEquals(json, serialized, JSONCompareMode.STRICT);
+ XChainCountWrapper deserialized = objectMapper.readValue(
+ serialized, XChainCountWrapper.class
+ );
+ Assertions.assertThat(deserialized).isEqualTo(wrapper);
+ }
+
+ @Value.Immutable
+ @JsonSerialize(as = ImmutableXChainCountWrapper.class)
+ @JsonDeserialize(as = ImmutableXChainCountWrapper.class)
+ interface XChainCountWrapper {
+
+ static XChainCountWrapper of(XChainCount count) {
+ return ImmutableXChainCountWrapper.builder().count(count).build();
+ }
+
+ XChainCount count();
+
+ }
+}
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCreateBridgeTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCreateBridgeTest.java
new file mode 100644
index 000000000..f4bc61714
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCreateBridgeTest.java
@@ -0,0 +1,123 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+import org.xrpl.xrpl4j.model.ledger.Issue;
+
+class XChainCreateBridgeTest extends AbstractJsonTest {
+
+ @Test
+ void testJsonWithMinAccountCreateAmount() throws JSONException, JsonProcessingException {
+ XChainCreateBridge createBridge = baseBuilder()
+ .minAccountCreateAmount(XrpCurrencyAmount.ofDrops(1000000))
+ .build();
+
+ String json = String.format("\n" +
+ "{\n" +
+ " \"TransactionType\": \"XChainCreateBridge\",\n" +
+ " \"Account\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"SignatureReward\": \"200\",\n" +
+ " \"MinAccountCreateAmount\": \"1000000\",\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(createBridge, json);
+ }
+
+ @Test
+ void testJsonWithUnsetFlags() throws JSONException, JsonProcessingException {
+ XChainCreateBridge createBridge = baseBuilder()
+ .flags(TransactionFlags.UNSET)
+ .build();
+
+ String json = String.format("\n" +
+ "{\n" +
+ " \"TransactionType\": \"XChainCreateBridge\",\n" +
+ " \"Account\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"SignatureReward\": \"200\",\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"Flags\": 0,\n" +
+ " \"SigningPubKey\": %s\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(createBridge, json);
+ }
+
+
+ @Test
+ void testJsonWithFullyCanonicalSigFlags() throws JSONException, JsonProcessingException {
+ XChainCreateBridge createBridge = baseBuilder()
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .build();
+
+ String json = String.format("\n" +
+ "{\n" +
+ " \"TransactionType\": \"XChainCreateBridge\",\n" +
+ " \"Account\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"SignatureReward\": \"200\",\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"Flags\": %s,\n" +
+ " \"SigningPubKey\": %s\n" +
+ "}", TransactionFlags.FULLY_CANONICAL_SIG, ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(createBridge, json);
+ }
+
+ private ImmutableXChainCreateBridge.Builder baseBuilder() {
+ return XChainCreateBridge.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(Address.of("rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg"))
+ .signatureReward(XrpCurrencyAmount.ofDrops(200))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .signingPublicKey(ED_PUBLIC_KEY);
+ }
+
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCreateClaimIdTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCreateClaimIdTest.java
new file mode 100644
index 000000000..ec1824104
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainCreateClaimIdTest.java
@@ -0,0 +1,123 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+import org.xrpl.xrpl4j.model.ledger.Issue;
+
+class XChainCreateClaimIdTest extends AbstractJsonTest {
+
+ @Test
+ void testJsonWithEmptyFlags() throws JSONException, JsonProcessingException {
+ XChainCreateClaimId claimId = baseBuilder().build();
+
+ String json = String.format("\n" +
+ "{\n" +
+ " \"Account\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"OtherChainSource\": \"rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo\",\n" +
+ " \"TransactionType\": \"XChainCreateClaimID\",\n" +
+ " \"SignatureReward\": \"100\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(claimId, json);
+ }
+
+ @Test
+ void testJsonWithUnsetFlags() throws JSONException, JsonProcessingException {
+ XChainCreateClaimId claimId = baseBuilder()
+ .flags(TransactionFlags.UNSET)
+ .build();
+
+ String json = String.format("\n" +
+ "{\n" +
+ " \"Account\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"OtherChainSource\": \"rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo\",\n" +
+ " \"TransactionType\": \"XChainCreateClaimID\",\n" +
+ " \"SignatureReward\": \"100\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"Flags\": 0,\n" +
+ " \"SigningPubKey\": %s\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(claimId, json);
+ }
+
+ @Test
+ void testJsonWithFullyCanonicalSigFlags() throws JSONException, JsonProcessingException {
+ XChainCreateClaimId claimId = baseBuilder()
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .build();
+
+ String json = String.format("\n" +
+ "{\n" +
+ " \"Account\": \"rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw\",\n" +
+ " \"OtherChainSource\": \"rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo\",\n" +
+ " \"TransactionType\": \"XChainCreateClaimID\",\n" +
+ " \"SignatureReward\": \"100\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"Flags\": %s,\n" +
+ " \"SigningPubKey\": %s\n" +
+ "}", TransactionFlags.FULLY_CANONICAL_SIG, ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(claimId, json);
+ }
+
+ private ImmutableXChainCreateClaimId.Builder baseBuilder() {
+ return XChainCreateClaimId.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(Address.of("rahDmoXrtPdh7sUdrPjini3gcnTVYjbjjw"))
+ .otherChainSource(Address.of("rMTi57fNy2UkUb4RcdoUeJm7gjxVQvxzUo"))
+ .signatureReward(XrpCurrencyAmount.ofDrops(100))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .signingPublicKey(ED_PUBLIC_KEY);
+ }
+
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainModifyBridgeTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainModifyBridgeTest.java
new file mode 100644
index 000000000..caa0a86d3
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/XChainModifyBridgeTest.java
@@ -0,0 +1,146 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.flags.XChainModifyBridgeFlags;
+import org.xrpl.xrpl4j.model.ledger.Issue;
+
+class XChainModifyBridgeTest extends AbstractJsonTest {
+
+ @Test
+ void testWithEmptySigRewardAndMinAccountCreateAmount() throws JSONException, JsonProcessingException {
+ XChainModifyBridge modify = baseBuilder().build();
+
+ String json = String.format("\n" +
+ "{\n" +
+ " \"TransactionType\": \"XChainModifyBridge\",\n" +
+ " \"Account\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SigningPubKey\": %s\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(modify, json);
+ }
+
+ @Test
+ void testWithUnsetFlags() throws JSONException, JsonProcessingException {
+ XChainModifyBridge modify = baseBuilder()
+ .flags(XChainModifyBridgeFlags.UNSET)
+ .build();
+
+ String json = String.format("\n" +
+ "{\n" +
+ " \"TransactionType\": \"XChainModifyBridge\",\n" +
+ " \"Account\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"Flags\": 0,\n" +
+ " \"SigningPubKey\": %s\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(modify, json);
+ }
+
+ @Test
+ void testWithClearAccountCreateAmountFlags() throws JSONException, JsonProcessingException {
+ XChainModifyBridge modify = baseBuilder()
+ .flags(XChainModifyBridgeFlags.CLEAR_ACCOUNT_CREATE_AMOUNT)
+ .build();
+
+ String json = String.format("\n" +
+ "{\n" +
+ " \"TransactionType\": \"XChainModifyBridge\",\n" +
+ " \"Account\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"Flags\": %s,\n" +
+ " \"SigningPubKey\": %s\n" +
+ "}", XChainModifyBridgeFlags.CLEAR_ACCOUNT_CREATE_AMOUNT, ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(modify, json);
+ }
+
+ @Test
+ void testWithSigRewardAndMinAccountCreateAmount() throws JSONException, JsonProcessingException {
+ XChainModifyBridge modify = baseBuilder()
+ .signatureReward(XrpCurrencyAmount.ofDrops(200))
+ .minAccountCreateAmount(XrpCurrencyAmount.ofDrops(1000000))
+ .build();
+
+ String json = String.format("\n" +
+ "{\n" +
+ " \"TransactionType\": \"XChainModifyBridge\",\n" +
+ " \"Account\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"XChainBridge\": {\n" +
+ " \"LockingChainDoor\": \"rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg\",\n" +
+ " \"LockingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " },\n" +
+ " \"IssuingChainDoor\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"IssuingChainIssue\": {\n" +
+ " \"currency\": \"XRP\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 1,\n" +
+ " \"SignatureReward\": \"200\",\n" +
+ " \"MinAccountCreateAmount\": \"1000000\",\n" +
+ " \"SigningPubKey\": %s\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(modify, json);
+ }
+
+ private ImmutableXChainModifyBridge.Builder baseBuilder() {
+ return XChainModifyBridge.builder()
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.ONE)
+ .account(Address.of("rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg"))
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(Address.of("rhWQzvdmhf5vFS35vtKUSUwNZHGT53qQsg"))
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .signingPublicKey(ED_PUBLIC_KEY);
+ }
+
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryTypeTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryTypeTest.java
index 03ce8f461..b9c18e6dd 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryTypeTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryTypeTest.java
@@ -8,6 +8,7 @@
import org.immutables.value.Value;
import org.junit.jupiter.api.Test;
import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.ledger.AccountRootObject;
class MetaLedgerEntryTypeTest extends AbstractJsonTest {
@@ -30,6 +31,37 @@ void testConstants() {
assertThat(MetaLedgerEntryType.TICKET.value()).isEqualTo("Ticket");
assertThat(MetaLedgerEntryType.NFTOKEN_PAGE.value()).isEqualTo("NFTokenPage");
assertThat(MetaLedgerEntryType.AMM.value()).isEqualTo("AMM");
+ assertThat(MetaLedgerEntryType.BRIDGE.value()).isEqualTo("Bridge");
+ assertThat(MetaLedgerEntryType.XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID.value())
+ .isEqualTo("XChainOwnedCreateAccountClaimID");
+ assertThat(MetaLedgerEntryType.XCHAIN_OWNED_CLAIM_ID.value()).isEqualTo("XChainOwnedClaimID");
+ }
+
+ @Test
+ void testLedgerObjectType() {
+ assertThat(MetaLedgerEntryType.ACCOUNT_ROOT.ledgerObjectType()).isEqualTo(MetaAccountRootObject.class);
+ assertThat(MetaLedgerEntryType.AMENDMENTS.ledgerObjectType()).isEqualTo(MetaUnknownObject.class);
+ assertThat(MetaLedgerEntryType.CHECK.ledgerObjectType()).isEqualTo(MetaCheckObject.class);
+ assertThat(MetaLedgerEntryType.DEPOSIT_PRE_AUTH.ledgerObjectType()).isEqualTo(MetaDepositPreAuthObject.class);
+ assertThat(MetaLedgerEntryType.DIRECTORY_NODE.ledgerObjectType()).isEqualTo(MetaUnknownObject.class);
+ assertThat(MetaLedgerEntryType.ESCROW.ledgerObjectType()).isEqualTo(MetaEscrowObject.class);
+ assertThat(MetaLedgerEntryType.FEE_SETTINGS.ledgerObjectType()).isEqualTo(MetaUnknownObject.class);
+ assertThat(MetaLedgerEntryType.LEDGER_HASHES.ledgerObjectType()).isEqualTo(MetaUnknownObject.class);
+ assertThat(MetaLedgerEntryType.NEGATIVE_UNL.ledgerObjectType()).isEqualTo(MetaUnknownObject.class);
+ assertThat(MetaLedgerEntryType.NFTOKEN_OFFER.ledgerObjectType()).isEqualTo(MetaNfTokenOfferObject.class);
+ assertThat(MetaLedgerEntryType.OFFER.ledgerObjectType()).isEqualTo(MetaOfferObject.class);
+ assertThat(MetaLedgerEntryType.PAY_CHANNEL.ledgerObjectType()).isEqualTo(MetaPayChannelObject.class);
+ assertThat(MetaLedgerEntryType.RIPPLE_STATE.ledgerObjectType()).isEqualTo(MetaRippleStateObject.class);
+ assertThat(MetaLedgerEntryType.SIGNER_LIST.ledgerObjectType()).isEqualTo(MetaSignerListObject.class);
+ assertThat(MetaLedgerEntryType.TICKET.ledgerObjectType()).isEqualTo(MetaTicketObject.class);
+ assertThat(MetaLedgerEntryType.NFTOKEN_PAGE.ledgerObjectType()).isEqualTo(MetaNfTokenPageObject.class);
+ assertThat(MetaLedgerEntryType.AMM.ledgerObjectType()).isEqualTo(MetaAmmObject.class);
+ assertThat(MetaLedgerEntryType.BRIDGE.ledgerObjectType()).isEqualTo(MetaBridgeObject.class);
+ assertThat(MetaLedgerEntryType.XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID.ledgerObjectType())
+ .isEqualTo(MetaXChainOwnedCreateAccountClaimIdObject.class);
+ assertThat(MetaLedgerEntryType.XCHAIN_OWNED_CLAIM_ID.ledgerObjectType()).isEqualTo(
+ MetaXChainOwnedClaimIdObject.class
+ );
}
@Test
diff --git a/xrpl4j-core/src/test/resources/codec-fixtures.json b/xrpl4j-core/src/test/resources/codec-fixtures.json
index e05cff35f..b9a43d13c 100644
--- a/xrpl4j-core/src/test/resources/codec-fixtures.json
+++ b/xrpl4j-core/src/test/resources/codec-fixtures.json
@@ -33,7 +33,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "059D1E86DE5DCCCF956BF4799675B2425AF9AD44FE4CCA6FEE1C812EEF6423E6",
- "Indexes": ["908D554AA0D29F660716A3EE65C61DD886B744DDF60DE70E6B16EADB770635DB"]
+ "Indexes": [
+ "908D554AA0D29F660716A3EE65C61DD886B744DDF60DE70E6B16EADB770635DB"
+ ]
}
},
{
@@ -327,7 +329,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "17CC40C6872E0C0E658C49B75D0812A70D4161DDA53324DF51FA58D3819C814B",
- "Indexes": ["571BF14F28C4D97871CDACD344A8CF57E6BA287BF0440B9E0D0683D02751CC7B"]
+ "Indexes": [
+ "571BF14F28C4D97871CDACD344A8CF57E6BA287BF0440B9E0D0683D02751CC7B"
+ ]
}
},
{
@@ -376,7 +380,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "1BCA9161A199AD5E907751CBF3FBA49689D517F0E8EE823AE17B737039B41DE1",
- "Indexes": ["26B894EE68470AD5AEEB55D5EBF936E6397CEE6957B93C56A2E7882CA9082873"]
+ "Indexes": [
+ "26B894EE68470AD5AEEB55D5EBF936E6397CEE6957B93C56A2E7882CA9082873"
+ ]
}
},
{
@@ -440,7 +446,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "1F9FF48419CA69FDDCC294CCEEE608F5F8A8BE11E286AD5743ED2D457C5570C4",
- "Indexes": ["7D4325BE338A40BBCBCC1F351B3272EB3E76305A878E76603DE206A795871619"]
+ "Indexes": [
+ "7D4325BE338A40BBCBCC1F351B3272EB3E76305A878E76603DE206A795871619"
+ ]
}
},
{
@@ -606,7 +614,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "289CFC476B5876F28C8A3B3C5B7058EC2BDF668C37B846EA7E5E1A73A4AA0816",
- "Indexes": ["BC10E40AFB79298004CDE51CB065DBDCABA86EC406E3A1CF02CE5F8A9628A2BD"]
+ "Indexes": [
+ "BC10E40AFB79298004CDE51CB065DBDCABA86EC406E3A1CF02CE5F8A9628A2BD"
+ ]
}
},
{
@@ -709,7 +719,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "2C9F00EFA5CCBD43452EF364B12C8DFCEF2B910336E5EFCE3AA412A556991582",
- "Indexes": ["F721E924498EE68BFF906CD856E8332073DD350BAC9E8977AC3F31860BA1E33A"]
+ "Indexes": [
+ "F721E924498EE68BFF906CD856E8332073DD350BAC9E8977AC3F31860BA1E33A"
+ ]
}
},
{
@@ -746,7 +758,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "2FB4904ACFB96228FC002335B1B5A4C5584D9D727BBE82144F0415EB4EA0C727",
- "Indexes": ["5F22826818CC83448C9DF34939AB4019D3F80C70DEB8BDBDCF0496A36DC68719"],
+ "Indexes": [
+ "5F22826818CC83448C9DF34939AB4019D3F80C70DEB8BDBDCF0496A36DC68719"
+ ],
"TakerPaysIssuer": "2B6C42A95B3F7EE1971E4A10098E8F1B5F66AA08"
}
},
@@ -760,7 +774,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "2FB4904ACFB96228FC002335B1B5A4C5584D9D727BBE82145003BAF82D03A000",
- "Indexes": ["5B7F148A8DDB4EB7386C9E75C4C1ED918DEDE5C52D5BA51B694D7271EF8BDB46"],
+ "Indexes": [
+ "5B7F148A8DDB4EB7386C9E75C4C1ED918DEDE5C52D5BA51B694D7271EF8BDB46"
+ ],
"TakerPaysIssuer": "2B6C42A95B3F7EE1971E4A10098E8F1B5F66AA08"
}
},
@@ -951,7 +967,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "3F2BADB38F12C87D111D3970CD1F05FE698DB86F14DC7C5FAEB05BFB6391B00E",
- "Indexes": ["73E075E64CA5E7CE60FFCD5359C1D730EDFFEE7C4D992760A87DF7EA0A34E40F"]
+ "Indexes": [
+ "73E075E64CA5E7CE60FFCD5359C1D730EDFFEE7C4D992760A87DF7EA0A34E40F"
+ ]
}
},
{
@@ -976,7 +994,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "4235CD082112FB621C02D6DA2E4F4ACFAFC91CB0585E034B936C29ABF4A76B01",
- "Indexes": ["6C4C3F1C6B9D76A6EF50F377E7C3991825694C604DBE0C1DD09362045EE41997"]
+ "Indexes": [
+ "6C4C3F1C6B9D76A6EF50F377E7C3991825694C604DBE0C1DD09362045EE41997"
+ ]
}
},
{
@@ -1075,7 +1095,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "48E91FD14597FB089654DADE7B70EB08CAF421EA611D703F3E871F7D4B5AAB5D",
- "Indexes": ["25DCAC87FBE4C3B66A1AFDE3C3F98E5A16333975C4FD46682F7497F27DFB9766"]
+ "Indexes": [
+ "25DCAC87FBE4C3B66A1AFDE3C3F98E5A16333975C4FD46682F7497F27DFB9766"
+ ]
}
},
{
@@ -1137,7 +1159,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "4EFC0442D07AE681F7FDFAA89C75F06F8E28CFF888593440201B0320E8F2C7BD",
- "Indexes": ["1595E5D5197330F58A479200A2FDD434D7A244BD1FFEC5E5EE8CF064AE77D3F5"]
+ "Indexes": [
+ "1595E5D5197330F58A479200A2FDD434D7A244BD1FFEC5E5EE8CF064AE77D3F5"
+ ]
}
},
{
@@ -1351,7 +1375,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "98082E695CAB618590BEEA0647A5F24D2B610A686ECD49310604FC7431FAAB0D",
- "Indexes": ["9BF3216E42575CA5A3CB4D0F2021EE81D0F7835BA2EDD78E05CAB44B655962BB"]
+ "Indexes": [
+ "9BF3216E42575CA5A3CB4D0F2021EE81D0F7835BA2EDD78E05CAB44B655962BB"
+ ]
}
},
{
@@ -1556,7 +1582,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "62AE37A44FE44BDCFC2BA5DD14D74BEC0AC346DA2DC1F04756044364C5BB0000",
- "Indexes": ["600A398F57CAE44461B4C8C25DE12AC289F87ED125438440B33B97417FE3D82C"],
+ "Indexes": [
+ "600A398F57CAE44461B4C8C25DE12AC289F87ED125438440B33B97417FE3D82C"
+ ],
"TakerPaysIssuer": "2B6C42A95B3F7EE1971E4A10098E8F1B5F66AA08"
}
},
@@ -1932,7 +1960,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "72D60CCD3905A3ABE19049B6EE76E8E0F3A2CBAC852625C757176F1B73EF617F",
- "Indexes": ["AB124EEAB087452070EC70D9DEA1A22C9766FFBBEE1025FD46495CC74148CCA8"]
+ "Indexes": [
+ "AB124EEAB087452070EC70D9DEA1A22C9766FFBBEE1025FD46495CC74148CCA8"
+ ]
}
},
{
@@ -2061,7 +2091,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "80AB25842B230D48027800213EB86023A3EAF4430E22C092D333795FFF1E5219",
- "Indexes": ["42E28285A82D01DCA856118A064C8AEEE1BF8167C08186DA5BFC678687E86F7C"]
+ "Indexes": [
+ "42E28285A82D01DCA856118A064C8AEEE1BF8167C08186DA5BFC678687E86F7C"
+ ]
}
},
{
@@ -2186,7 +2218,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "8ADF3C5527CCF6D0B5863365EF40254171536C3901F1CBD9E2BC5F918A7D492A",
- "Indexes": ["BC10E40AFB79298004CDE51CB065DBDCABA86EC406E3A1CF02CE5F8A9628A2BD"]
+ "Indexes": [
+ "BC10E40AFB79298004CDE51CB065DBDCABA86EC406E3A1CF02CE5F8A9628A2BD"
+ ]
}
},
{
@@ -2587,7 +2621,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "A00CD19C13A5CFA3FECB409D42B38017C07A4AEAE05A7A00347DDA17199BA683",
- "Indexes": ["E49318D6DF22411C3F35581B1D28297A36E47F68B45F36A587C156E6E43CE0A6"]
+ "Indexes": [
+ "E49318D6DF22411C3F35581B1D28297A36E47F68B45F36A587C156E6E43CE0A6"
+ ]
}
},
{
@@ -2634,7 +2670,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "A39F044D860C5B5846AA7E0FAAD44DC8897F0A62B2F628AA073B21B3EC146010",
- "Indexes": ["CD34D8FF7C656B66E2298DB420C918FE27DFFF2186AC8D1785D8CBF2C6BC3488"]
+ "Indexes": [
+ "CD34D8FF7C656B66E2298DB420C918FE27DFFF2186AC8D1785D8CBF2C6BC3488"
+ ]
}
},
{
@@ -2683,7 +2721,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "A7E461C6DC98F472991FDE51FADDC0082D755F553F5849875D554B52624EF1C3",
- "Indexes": ["116C6D5E5C6C59C9C5362B84CB9DD30BD3D4B7CB98CE993D49C068323BF19747"]
+ "Indexes": [
+ "116C6D5E5C6C59C9C5362B84CB9DD30BD3D4B7CB98CE993D49C068323BF19747"
+ ]
}
},
{
@@ -2717,7 +2757,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "AA539C8EECE0A0CFF0DBF3BFACD6B42CD4421715428AD90B034091BD3C721038",
- "Indexes": ["72307CB57E53604A0C50E653AB10E386F3835460B5585B70CB7F668C1E04AC8B"]
+ "Indexes": [
+ "72307CB57E53604A0C50E653AB10E386F3835460B5585B70CB7F668C1E04AC8B"
+ ]
}
},
{
@@ -3777,7 +3819,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "D4A00D9B3452C7F93C5F0531FA8FFB4599FEEC405CA803FBEFE0FA22137D863D",
- "Indexes": ["C1C5FB39D6C15C581D822DBAF725EF7EDE40BEC9F93C52398CF5CE9F64154D6C"]
+ "Indexes": [
+ "C1C5FB39D6C15C581D822DBAF725EF7EDE40BEC9F93C52398CF5CE9F64154D6C"
+ ]
}
},
{
@@ -3787,7 +3831,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "D4B68B54869E428428078E1045B8BB66C24DD101DB3FCCBB099929B3B63BCB40",
- "Indexes": ["9A551971E78FE2FB80D930A77EA0BAC2139A49D6BEB98406427C79F52A347A09"]
+ "Indexes": [
+ "9A551971E78FE2FB80D930A77EA0BAC2139A49D6BEB98406427C79F52A347A09"
+ ]
}
},
{
@@ -3862,7 +3908,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "DD23E2C60C9BC58180AC6EA7C668233EC51A0947E42FD1FAD4F5FBAED9698D95",
- "Indexes": ["908D554AA0D29F660716A3EE65C61DD886B744DDF60DE70E6B16EADB770635DB"]
+ "Indexes": [
+ "908D554AA0D29F660716A3EE65C61DD886B744DDF60DE70E6B16EADB770635DB"
+ ]
}
},
{
@@ -4013,7 +4061,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "E2EC9E1BC7B4667B7A5F2F68857F6E6A478A09B5BB4F99E09F694437C4152DED",
- "Indexes": ["65492B9F30F1CBEA168509128EB8619BAE02A7A7A4725FF3F8DAA70FA707A26E"]
+ "Indexes": [
+ "65492B9F30F1CBEA168509128EB8619BAE02A7A7A4725FF3F8DAA70FA707A26E"
+ ]
}
},
{
@@ -4190,7 +4240,9 @@
"IndexPrevious": "0000000000000002",
"Flags": 0,
"RootIndex": "8E92E688A132410427806A734DF6154B7535E439B72DECA5E4BC7CE17135C5A4",
- "Indexes": ["73E075E64CA5E7CE60FFCD5359C1D730EDFFEE7C4D992760A87DF7EA0A34E40F"]
+ "Indexes": [
+ "73E075E64CA5E7CE60FFCD5359C1D730EDFFEE7C4D992760A87DF7EA0A34E40F"
+ ]
}
},
{
@@ -4294,7 +4346,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "F774E0321809251174AC85531606FB46B75EEF9F842F9697531AA535D3D0C000",
- "Indexes": ["D1CB738BD08AC36DCB77191DB87C6E40FA478B86503371ED497F30931D7F4F52"],
+ "Indexes": [
+ "D1CB738BD08AC36DCB77191DB87C6E40FA478B86503371ED497F30931D7F4F52"
+ ],
"TakerPaysIssuer": "E8ACFC6B5EF4EA0601241525375162F43C2FF285"
}
},
@@ -4355,7 +4409,9 @@
"LedgerEntryType": "DirectoryNode",
"Flags": 0,
"RootIndex": "F95F6D3A1EF7981E5CA4D5AEC4DA63392B126C76469735BCCA26150A1AF6D9C3",
- "Indexes": ["CAD951AB279A749AE648FD1DFF56C021BD66E36187022E772C31FE52106CB13B"]
+ "Indexes": [
+ "CAD951AB279A749AE648FD1DFF56C021BD66E36187022E772C31FE52106CB13B"
+ ]
}
},
{
@@ -4435,20 +4491,230 @@
}
}
],
- "transactions": [{
- "binary": "1200002200000000240000003E6140000002540BE40068400000000000000A7321034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E74473045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F17962646398114550FC62003E785DC231A1058A05E56E3F09CF4E68314D4CC8AB5B21D86A82C3E9E8D0ECF2404B77FECBA",
- "json": {
- "Account": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
- "Destination": "rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj",
- "TransactionType": "Payment",
- "TxnSignature": "3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639",
- "SigningPubKey": "034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E",
- "Amount": "10000000000",
- "Fee": "10",
- "Flags": 0,
- "Sequence": 62
- }
- },
+ "transactions": [
+ {
+ "binary": "1200002200000000240000003E6140000002540BE40068400000000000000A7321034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E74473045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F17962646398114550FC62003E785DC231A1058A05E56E3F09CF4E68314D4CC8AB5B21D86A82C3E9E8D0ECF2404B77FECBA",
+ "json": {
+ "Account": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
+ "Destination": "rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj",
+ "TransactionType": "Payment",
+ "TxnSignature": "3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639",
+ "SigningPubKey": "034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E",
+ "Amount": "10000000000",
+ "Fee": "10",
+ "Flags": 0,
+ "Sequence": 62
+ }
+ },
+ {
+ "binary": "1200302200000000240000000168400000000000000A601D40000000000003E8601E400000000000271073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020744630440220101BCA4B5B5A37C6F44480F9A34752C9AA8B2CDF5AD47E3CB424DEDC21C06DB702206EEB257E82A89B1F46A0A2C7F070B0BD181D980FF86FE4269E369F6FC7A270918114B5F762798A53D543A014CAF8B297CFF8F2F937E8011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
+ "json": {
+ "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "XChainBridge": {
+ "LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
+ "LockingChainIssue": {
+ "currency": "XRP"
+ },
+ "IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
+ "IssuingChainIssue": {
+ "currency": "XRP"
+ }
+ },
+ "Fee": "10",
+ "Flags": 0,
+ "MinAccountCreateAmount": "10000",
+ "Sequence": 1,
+ "SignatureReward": "1000",
+ "SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
+ "TransactionType": "XChainCreateBridge",
+ "TxnSignature": "30440220101BCA4B5B5A37C6F44480F9A34752C9AA8B2CDF5AD47E3CB424DEDC21C06DB702206EEB257E82A89B1F46A0A2C7F070B0BD181D980FF86FE4269E369F6FC7A27091"
+ }
+ },
+ {
+ "binary": "12002F2200000000240000000168400000000000000A601D40000000000003E8601E400000000000271073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02074473045022100D2CABC1B0E0635A8EE2E6554F6D474C49BC292C995C5C9F83179F4A60634B04C02205D1DB569D9593136F2FBEA7140010C8F46794D653AFDBEA8D30B8750BA4805E58114B5F762798A53D543A014CAF8B297CFF8F2F937E8011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
+ "json": {
+ "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "XChainBridge": {
+ "LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
+ "LockingChainIssue": {
+ "currency": "XRP"
+ },
+ "IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
+ "IssuingChainIssue": {
+ "currency": "XRP"
+ }
+ },
+ "Fee": "10",
+ "Flags": 0,
+ "MinAccountCreateAmount": "10000",
+ "Sequence": 1,
+ "SignatureReward": "1000",
+ "SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
+ "TransactionType": "XChainModifyBridge",
+ "TxnSignature": "3045022100D2CABC1B0E0635A8EE2E6554F6D474C49BC292C995C5C9F83179F4A60634B04C02205D1DB569D9593136F2FBEA7140010C8F46794D653AFDBEA8D30B8750BA4805E5"
+ }
+ },
+ {
+ "binary": "1200292280000000240000000168400000000000000A601D400000000000271073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020744630440220247B20A1B9C48E21A374CB9B3E1FE2A7C528151868DF8D307E9FBE15237E531A02207C20C092DDCC525E583EF4AB7CB91E862A6DED19426997D3F0A2C84E2BE8C5DD8114B5F762798A53D543A014CAF8B297CFF8F2F937E8801214AF80285F637EE4AF3C20378F9DFB12511ACB8D27011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
+ "json": {
+ "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "XChainBridge": {
+ "LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
+ "LockingChainIssue": {
+ "currency": "XRP"
+ },
+ "IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
+ "IssuingChainIssue": {
+ "currency": "XRP"
+ }
+ },
+ "Fee": "10",
+ "Flags": 2147483648,
+ "OtherChainSource": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
+ "Sequence": 1,
+ "SignatureReward": "10000",
+ "SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
+ "TransactionType": "XChainCreateClaimID",
+ "TxnSignature": "30440220247B20A1B9C48E21A374CB9B3E1FE2A7C528151868DF8D307E9FBE15237E531A02207C20C092DDCC525E583EF4AB7CB91E862A6DED19426997D3F0A2C84E2BE8C5DD"
+ }
+ },
+ {
+ "binary": "12002A228000000024000000013014000000000000000161400000000000271068400000000000000A73210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02074453043021F177323F0D93612C82A4393A99B23905A7E675753FD80C52997AFAB13F5F9D002203BFFAF457E90BDA65AABE8F8762BD96162FAD98A0C030CCD69B06EE9B12BBFFE8114B5F762798A53D543A014CAF8B297CFF8F2F937E8011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
+ "json": {
+ "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "Amount": "10000",
+ "XChainBridge": {
+ "LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
+ "LockingChainIssue": {
+ "currency": "XRP"
+ },
+ "IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
+ "IssuingChainIssue": {
+ "currency": "XRP"
+ }
+ },
+ "Fee": "10",
+ "Flags": 2147483648,
+ "Sequence": 1,
+ "SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
+ "TransactionType": "XChainCommit",
+ "TxnSignature": "3043021F177323F0D93612C82A4393A99B23905A7E675753FD80C52997AFAB13F5F9D002203BFFAF457E90BDA65AABE8F8762BD96162FAD98A0C030CCD69B06EE9B12BBFFE",
+ "XChainClaimID": "1"
+ }
+ },
+ {
+ "binary": "12002B228000000024000000013014000000000000000161400000000000271068400000000000000A73210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020744630440220445F7469FDA401787D9EE8A9B6E24DFF81E94F4C09FD311D2C0A58FCC02C684A022029E2EF34A5EA35F50D5BB57AC6320AD3AE12C13C8D1379B255A486D72CED142E8114B5F762798A53D543A014CAF8B297CFF8F2F937E88314550FC62003E785DC231A1058A05E56E3F09CF4E6011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
+ "json": {
+ "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "Amount": "10000",
+ "XChainBridge": {
+ "LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
+ "LockingChainIssue": {
+ "currency": "XRP"
+ },
+ "IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
+ "IssuingChainIssue": {
+ "currency": "XRP"
+ }
+ },
+ "Destination": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
+ "Fee": "10",
+ "Flags": 2147483648,
+ "Sequence": 1,
+ "SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
+ "TransactionType": "XChainClaim",
+ "TxnSignature": "30440220445F7469FDA401787D9EE8A9B6E24DFF81E94F4C09FD311D2C0A58FCC02C684A022029E2EF34A5EA35F50D5BB57AC6320AD3AE12C13C8D1379B255A486D72CED142E",
+ "XChainClaimID": "1"
+ }
+ },
+ {
+ "binary": "12002C228000000024000000016140000000000F424068400000000000000A601D400000000000271073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD0207446304402202984DDE7F0B566F081F7953D7212BF031ACBF8860FE114102E9512C4C8768C77022070113F4630B1DC3045E4A98DDD648CEBC31B12774F7B44A1B8123CD2C9F5CF188114B5F762798A53D543A014CAF8B297CFF8F2F937E88314AF80285F637EE4AF3C20378F9DFB12511ACB8D27011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
+ "json": {
+ "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "XChainBridge": {
+ "LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
+ "LockingChainIssue": {
+ "currency": "XRP"
+ },
+ "IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
+ "IssuingChainIssue": {
+ "currency": "XRP"
+ }
+ },
+ "Amount": "1000000",
+ "Fee": "10",
+ "Flags": 2147483648,
+ "Destination": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
+ "Sequence": 1,
+ "SignatureReward": "10000",
+ "SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
+ "TransactionType": "XChainAccountCreateCommit",
+ "TxnSignature": "304402202984DDE7F0B566F081F7953D7212BF031ACBF8860FE114102E9512C4C8768C77022070113F4630B1DC3045E4A98DDD648CEBC31B12774F7B44A1B8123CD2C9F5CF18"
+ }
+ },
+ {
+ "binary": "12002E2400000005201B0000000D30150000000000000006614000000000989680684000000000000014601D40000000000000647121ED1F4A024ACFEBDB6C7AA88DEDE3364E060487EA31B14CC9E0D610D152B31AADC27321EDF54108BA2E0A0D3DC2AE3897F8BE0EFE776AE8D0F9FB0D0B9D64233084A8DDD1744003E74AEF1F585F156786429D2FC87A89E5C6B5A56D68BFC9A6A329F3AC67CBF2B6958283C663A4522278CA162C69B23CF75149AF022B410EA0508C16F42058007640EEFCFA3DC2AB4AB7C4D2EBBC168CB621A11B82BABD86534DFC8EFA72439A49662D744073CD848E7A587A95B35162CDF9A69BB237E72C9537A987F5B8C394F30D81145E7A3E3D7200A794FA801C66CE3775B6416EE4128314C15F113E49BCC4B9FFF43CD0366C23ACD82F75638012143FD9ED9A79DEA67CB5D585111FEF0A29203FA0408014145E7A3E3D7200A794FA801C66CE3775B6416EE4128015145E7A3E3D7200A794FA801C66CE3775B6416EE4120010130101191486F0B1126CE1205E59FDFDD2661A9FB7505CA70F000000000000000000000000000000000000000014B5F762798A53D543A014CAF8B297CFF8F2F937E80000000000000000000000000000000000000000",
+ "json": {
+ "Account": "r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT",
+ "Amount": "10000000",
+ "AttestationRewardAccount": "r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT",
+ "AttestationSignerAccount": "r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT",
+ "Destination": "rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi",
+ "Fee": "20",
+ "LastLedgerSequence": 13,
+ "OtherChainSource": "raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym",
+ "PublicKey": "ED1F4A024ACFEBDB6C7AA88DEDE3364E060487EA31B14CC9E0D610D152B31AADC2",
+ "Sequence": 5,
+ "Signature": "EEFCFA3DC2AB4AB7C4D2EBBC168CB621A11B82BABD86534DFC8EFA72439A49662D744073CD848E7A587A95B35162CDF9A69BB237E72C9537A987F5B8C394F30D",
+ "SignatureReward": "100",
+ "SigningPubKey": "EDF54108BA2E0A0D3DC2AE3897F8BE0EFE776AE8D0F9FB0D0B9D64233084A8DDD1",
+ "TransactionType": "XChainAddAccountCreateAttestation",
+ "TxnSignature": "03E74AEF1F585F156786429D2FC87A89E5C6B5A56D68BFC9A6A329F3AC67CBF2B6958283C663A4522278CA162C69B23CF75149AF022B410EA0508C16F4205800",
+ "WasLockingChainSend": 1,
+ "XChainAccountCreateCount": "6",
+ "XChainBridge": {
+ "IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "IssuingChainIssue": {
+ "currency": "XRP"
+ },
+ "LockingChainDoor": "rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg",
+ "LockingChainIssue": {
+ "currency": "XRP"
+ }
+ }
+ }
+ },
+ {
+ "binary": "12002D2400000009201B00000013301400000000000000016140000000009896806840000000000000147121ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E11367321ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C7440D0423649E48A44F181262CF5FC08A68E7FA5CD9E55843E4F09014B76E602574741E8553383A4B43CABD194BB96713647FC0B885BE248E4FFA068FA3E6994CF0476407C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44528FE99AA50E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C81141F30A4D728AB98B0950EC3B9815E6C8D43A7D5598314C15F113E49BCC4B9FFF43CD0366C23ACD82F75638012143FD9ED9A79DEA67CB5D585111FEF0A29203FA0408014141F30A4D728AB98B0950EC3B9815E6C8D43A7D5598015141F30A4D728AB98B0950EC3B9815E6C8D43A7D5590010130101191486F0B1126CE1205E59FDFDD2661A9FB7505CA70F000000000000000000000000000000000000000014B5F762798A53D543A014CAF8B297CFF8F2F937E80000000000000000000000000000000000000000",
+ "json": {
+ "Account": "rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3",
+ "Amount": "10000000",
+ "AttestationRewardAccount": "rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3",
+ "AttestationSignerAccount": "rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3",
+ "Destination": "rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi",
+ "Fee": "20",
+ "LastLedgerSequence": 19,
+ "OtherChainSource": "raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym",
+ "PublicKey": "ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E1136",
+ "Sequence": 9,
+ "Signature": "7C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44528FE99AA50E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C",
+ "SigningPubKey": "ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C",
+ "TransactionType": "XChainAddClaimAttestation",
+ "TxnSignature": "D0423649E48A44F181262CF5FC08A68E7FA5CD9E55843E4F09014B76E602574741E8553383A4B43CABD194BB96713647FC0B885BE248E4FFA068FA3E6994CF04",
+ "WasLockingChainSend": 1,
+ "XChainBridge": {
+ "IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "IssuingChainIssue": {
+ "currency": "XRP"
+ },
+ "LockingChainDoor": "rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg",
+ "LockingChainIssue": {
+ "currency": "XRP"
+ }
+ },
+ "XChainClaimID": "1"
+ }
+ },
{
"binary": "12002315000A2200000000240015DAE161400000000000271068400000000000000A6BD5838D7EA4C680000000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C7321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B87440B3154D968314FCEB58001E1B0C3A4CFB33DF9FF6C73207E5EAEB9BD07E2747672168E1A2786D950495C38BD8DEE3391BF45F3008DD36F4B12E7C07D82CA5250E8114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A",
"json": {
@@ -4474,9 +4740,18 @@
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMDeposit",
"TxnSignature": "8073C588E7EF672DD171E414638D9AF8DBE9A1359E030DE3E1C9AA6A38A2CE9E138CB56482BB844F7228D48B1E4AD7D09BB7E9F639C115958EEEA374749CA00B",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
- "LPTokenOut": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "1000"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
+ "LPTokenOut": {
+ "currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048",
+ "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg",
+ "value": "1000"
+ },
"Fee": "10",
"Flags": 65536,
"Sequence": 1432289,
@@ -4488,8 +4763,13 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMDeposit",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
"Amount": "1000",
"Fee": "10",
"Flags": 524288,
@@ -4503,10 +4783,19 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMDeposit",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
"Amount": "1000",
- "Amount2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9", "value": "500"},
+ "Amount2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9",
+ "value": "500"
+ },
"Fee": "10",
"Flags": 1048576,
"Sequence": 1432289,
@@ -4519,10 +4808,19 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMDeposit",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
"Amount": "1000",
- "LPTokenOut": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "1000"},
+ "LPTokenOut": {
+ "currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048",
+ "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg",
+ "value": "1000"
+ },
"Fee": "10",
"Flags": 2097152,
"Sequence": 1432289,
@@ -4535,8 +4833,13 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMDeposit",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
"Amount": "1000",
"EPrice": "25",
"Fee": "10",
@@ -4551,9 +4854,18 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMWithdraw",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
- "LPTokenIn": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "1000"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
+ "LPTokenIn": {
+ "currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048",
+ "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg",
+ "value": "1000"
+ },
"Fee": "10",
"Flags": 65536,
"Sequence": 1432289,
@@ -4566,8 +4878,13 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMWithdraw",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
"Amount": "1000",
"Fee": "10",
"Flags": 524288,
@@ -4581,10 +4898,19 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMWithdraw",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
"Amount": "1000",
- "Amount2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9", "value": "500"},
+ "Amount2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9",
+ "value": "500"
+ },
"Fee": "10",
"Flags": 1048576,
"Sequence": 1432289,
@@ -4597,10 +4923,19 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMWithdraw",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
"Amount": "1000",
- "LPTokenIn": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "1000"},
+ "LPTokenIn": {
+ "currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048",
+ "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg",
+ "value": "1000"
+ },
"Fee": "10",
"Flags": 2097152,
"Sequence": 1432289,
@@ -4613,8 +4948,13 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMWithdraw",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
"Amount": "1000",
"EPrice": "25",
"Fee": "10",
@@ -4629,11 +4969,30 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMBid",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
- "AuthAccounts": [{"AuthAccount": {"Account": "rEaHTti4HZsMBpxTAF4ncWxkcdqDh1h6P7"}}],
- "BidMax": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "35"},
- "BidMin": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "25"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
+ "AuthAccounts": [
+ {
+ "AuthAccount": {
+ "Account": "rEaHTti4HZsMBpxTAF4ncWxkcdqDh1h6P7"
+ }
+ }
+ ],
+ "BidMax": {
+ "currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048",
+ "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg",
+ "value": "35"
+ },
+ "BidMin": {
+ "currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048",
+ "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg",
+ "value": "25"
+ },
"Fee": "10",
"Flags": 0,
"Sequence": 1432289,
@@ -4646,8 +5005,13 @@
"json": {
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
"TransactionType": "AMMVote",
- "Asset": {"currency": "XRP"},
- "Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ "Asset": {
+ "currency": "XRP"
+ },
+ "Asset2": {
+ "currency": "ETH",
+ "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"
+ },
"TradingFee": 234,
"Fee": "10",
"Flags": 0,
@@ -4655,19 +5019,22 @@
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
"TxnSignature": "BC2F6E76969E3747E9BDE183C97573B086212F09D5387460E6EE2F32953E85EAEB9618FBBEF077276E30E59D619FCF7C7BDCDDDD9EB94D7CE1DD5CE9246B2107"
}
- }],
- "ledgerData": [{
- "binary": "01E91435016340767BF1C4A3EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F873B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D521276CDE21276CE60A00",
- "json": {
- "account_hash": "3B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D5",
- "close_flags": 0,
- "close_time": 556231910,
- "close_time_resolution": 10,
- "ledger_index": 32052277,
- "parent_close_time": 556231902,
- "parent_hash": "EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6",
- "total_coins": "99994494362043555",
- "transaction_hash": "DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F87"
}
- }]
+ ],
+ "ledgerData": [
+ {
+ "binary": "01E91435016340767BF1C4A3EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F873B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D521276CDE21276CE60A00",
+ "json": {
+ "account_hash": "3B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D5",
+ "close_flags": 0,
+ "close_time": 556231910,
+ "close_time_resolution": 10,
+ "ledger_index": 32052277,
+ "parent_close_time": 556231902,
+ "parent_hash": "EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6",
+ "total_coins": "99994494362043555",
+ "transaction_hash": "DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F87"
+ }
+ }
+ ]
}
\ No newline at end of file
diff --git a/xrpl4j-integration-tests/pom.xml b/xrpl4j-integration-tests/pom.xml
index ffa4fb1c2..eefdeccd5 100644
--- a/xrpl4j-integration-tests/pom.xml
+++ b/xrpl4j-integration-tests/pom.xml
@@ -28,6 +28,16 @@
jackson-core
test
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ test
+
+
+ org.immutables
+ value
+ test
+
com.fasterxml.jackson.core
jackson-databind
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AbstractIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AbstractIT.java
index 53307bcba..261e938de 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AbstractIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AbstractIT.java
@@ -27,6 +27,7 @@
import static org.hamcrest.core.Is.is;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedInteger;
import com.google.common.primitives.UnsignedLong;
import org.awaitility.Durations;
@@ -76,6 +77,7 @@
import org.xrpl.xrpl4j.model.transactions.TransactionResultCodes;
import org.xrpl.xrpl4j.model.transactions.TransactionType;
import org.xrpl.xrpl4j.model.transactions.TrustSet;
+import org.xrpl.xrpl4j.model.transactions.XChainCreateBridge;
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
import org.xrpl.xrpl4j.tests.environment.XrplEnvironment;
@@ -205,6 +207,35 @@ protected void fundAccount(final Address address) {
xrplEnvironment.fundAccount(address);
}
+ protected TransactionResult signSubmitAndWait(
+ T transaction,
+ KeyPair keyPair,
+ Class transactionType
+ )
+ throws JsonRpcClientErrorException, JsonProcessingException {
+ Preconditions.checkArgument(transaction.lastLedgerSequence().isPresent());
+
+ SingleSignedTransaction signedTransaction = signatureService.sign(
+ keyPair.privateKey(),
+ transaction
+ );
+
+ SubmitResult voteSubmitResult = xrplClient.submit(signedTransaction);
+ assertThat(voteSubmitResult.engineResult()).isEqualTo(TransactionResultCodes.TES_SUCCESS);
+
+ Finality finality = scanForFinality(
+ signedTransaction.hash(),
+ voteSubmitResult.validatedLedgerIndex(),
+ transaction.lastLedgerSequence().get(),
+ transaction.sequence(),
+ keyPair.publicKey().deriveAddress()
+ );
+
+ assertThat(finality.finalityStatus()).isEqualTo(FinalityStatus.VALIDATED_SUCCESS);
+
+ return this.getValidatedTransaction(signedTransaction.hash(), transactionType);
+ }
+
//////////////////////
// Ledger Helpers
//////////////////////
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/XChainIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/XChainIT.java
new file mode 100644
index 000000000..f98919765
--- /dev/null
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/XChainIT.java
@@ -0,0 +1,1040 @@
+package org.xrpl.xrpl4j.tests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNoException;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.immutables.value.Value;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIf;
+import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
+import org.xrpl.xrpl4j.crypto.keys.KeyPair;
+import org.xrpl.xrpl4j.crypto.keys.Seed;
+import org.xrpl.xrpl4j.crypto.signing.Signature;
+import org.xrpl.xrpl4j.model.AddressConstants;
+import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
+import org.xrpl.xrpl4j.model.client.accounts.AccountObjectsResult;
+import org.xrpl.xrpl4j.model.client.common.LedgerSpecifier;
+import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
+import org.xrpl.xrpl4j.model.client.ledger.LedgerEntryRequestParams;
+import org.xrpl.xrpl4j.model.client.ledger.LedgerEntryResult;
+import org.xrpl.xrpl4j.model.client.transactions.TransactionResult;
+import org.xrpl.xrpl4j.model.flags.XChainModifyBridgeFlags;
+import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory;
+import org.xrpl.xrpl4j.model.ledger.AttestationClaim;
+import org.xrpl.xrpl4j.model.ledger.AttestationCreateAccount;
+import org.xrpl.xrpl4j.model.ledger.BridgeObject;
+import org.xrpl.xrpl4j.model.ledger.Issue;
+import org.xrpl.xrpl4j.model.ledger.LedgerObject;
+import org.xrpl.xrpl4j.model.ledger.SignerEntry;
+import org.xrpl.xrpl4j.model.ledger.SignerEntryWrapper;
+import org.xrpl.xrpl4j.model.ledger.XChainClaimAttestation;
+import org.xrpl.xrpl4j.model.ledger.XChainClaimProofSig;
+import org.xrpl.xrpl4j.model.ledger.XChainCreateAccountAttestation;
+import org.xrpl.xrpl4j.model.ledger.XChainCreateAccountProofSig;
+import org.xrpl.xrpl4j.model.ledger.XChainOwnedClaimIdObject;
+import org.xrpl.xrpl4j.model.ledger.XChainOwnedCreateAccountClaimIdObject;
+import org.xrpl.xrpl4j.model.transactions.AccountSet;
+import org.xrpl.xrpl4j.model.transactions.AccountSet.AccountSetFlag;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.CurrencyAmount;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.IssuedCurrencyAmount;
+import org.xrpl.xrpl4j.model.transactions.SignerListSet;
+import org.xrpl.xrpl4j.model.transactions.TransactionMetadata;
+import org.xrpl.xrpl4j.model.transactions.XChainAccountCreateCommit;
+import org.xrpl.xrpl4j.model.transactions.XChainAddAccountCreateAttestation;
+import org.xrpl.xrpl4j.model.transactions.XChainAddClaimAttestation;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainClaim;
+import org.xrpl.xrpl4j.model.transactions.XChainClaimId;
+import org.xrpl.xrpl4j.model.transactions.XChainCommit;
+import org.xrpl.xrpl4j.model.transactions.XChainCount;
+import org.xrpl.xrpl4j.model.transactions.XChainCreateBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainCreateClaimId;
+import org.xrpl.xrpl4j.model.transactions.XChainModifyBridge;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+import org.xrpl.xrpl4j.model.transactions.metadata.AffectedNode;
+import org.xrpl.xrpl4j.model.transactions.metadata.CreatedNode;
+import org.xrpl.xrpl4j.model.transactions.metadata.DeletedNode;
+import org.xrpl.xrpl4j.model.transactions.metadata.ImmutableMetaXChainCreateAccountAttestation;
+import org.xrpl.xrpl4j.model.transactions.metadata.ImmutableMetaXChainCreateAccountProofSig;
+import org.xrpl.xrpl4j.model.transactions.metadata.MetaLedgerEntryType;
+import org.xrpl.xrpl4j.model.transactions.metadata.MetaXChainOwnedCreateAccountClaimIdObject;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+
+@DisabledIf(value = "shouldRun", disabledReason = "XChainIT only runs with local rippled nodes.")
+public class XChainIT extends AbstractIT {
+
+ static boolean shouldRun() {
+ return System.getProperty("useTestnet") != null ||
+ System.getProperty("useDevnet") != null ||
+ System.getProperty("useClioTestnet") != null;
+ }
+
+ TestBridge testBridge;
+
+ {
+ try {
+ testBridge = setupXrpToXrpBridge();
+ } catch (JsonRpcClientErrorException | JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ void testXChainAccountCreateCommit() throws JsonRpcClientErrorException, JsonProcessingException {
+ XrpCurrencyAmount initialDoorBalance = this.getValidatedAccountInfo(testBridge.bridge().lockingChainDoor())
+ .accountData()
+ .balance();
+
+ KeyPair sender = this.createRandomAccountEd25519();
+ KeyPair destination = Seed.ed25519Seed().deriveKeyPair();
+ XrpCurrencyAmount amount = XrpCurrencyAmount.ofDrops(10000000);
+
+ AccountInfoResult senderAccountInfo = this.scanForResult(
+ () -> getValidatedAccountInfo(sender.publicKey().deriveAddress())
+ );
+
+ FeeResult feeResult = xrplClient.fee();
+ XChainAccountCreateCommit transaction = XChainAccountCreateCommit.builder()
+ .account(sender.publicKey().deriveAddress())
+ .sequence(senderAccountInfo.accountData().sequence())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
+ .lastLedgerSequence(senderAccountInfo.ledgerIndexSafe().plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue())
+ .signingPublicKey(sender.publicKey())
+ .xChainBridge(testBridge.bridge())
+ .amount(amount)
+ .signatureReward(testBridge.signatureReward())
+ .destination(destination.publicKey().deriveAddress())
+ .build();
+
+ this.signSubmitAndWait(transaction, sender, XChainAccountCreateCommit.class);
+
+ XrpCurrencyAmount finalBalance = this.getValidatedAccountInfo(testBridge.bridge().lockingChainDoor())
+ .accountData()
+ .balance();
+
+ assertThat(finalBalance).isEqualTo(initialDoorBalance.plus(amount).plus(testBridge.signatureReward()));
+ }
+
+ @Test
+ void testXChainAddAccountCreateAttestation() throws JsonProcessingException, JsonRpcClientErrorException {
+ KeyPair source = this.createRandomAccountEd25519();
+ KeyPair destination = this.createRandomAccountEd25519();
+ KeyPair otherChainSource = this.createRandomAccountEd25519();
+
+ // Create an attestation for witness 1 to sign
+ AttestationCreateAccount attestation = AttestationCreateAccount.builder()
+ .xChainBridge(testBridge.bridge())
+ .otherChainSource(otherChainSource.publicKey().deriveAddress())
+ .amount(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(300)))
+ .attestationRewardAccount(testBridge.witnessKeyPair().publicKey().deriveAddress())
+ .wasLockingChainSend(false)
+ .destination(destination.publicKey().deriveAddress())
+ .signatureReward(testBridge.signatureReward())
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ONE))
+ .build();
+
+ // Witness 1 signs the attestation
+ Signature attestationSignature = signatureService.sign(testBridge.witnessKeyPair().privateKey(), attestation);
+
+ AccountInfoResult sourceAccountInfo = this.scanForResult(
+ () -> getValidatedAccountInfo(source.publicKey().deriveAddress())
+ );
+ FeeResult feeResult = xrplClient.fee();
+ // Add the attestation from Witness 1
+ XChainAddAccountCreateAttestation transaction = XChainAddAccountCreateAttestation.builder()
+ .account(source.publicKey().deriveAddress())
+ .xChainBridge(testBridge.bridge())
+ .otherChainSource(otherChainSource.publicKey().deriveAddress())
+ .amount(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(300)))
+ .wasLockingChainSend(false)
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ONE))
+ .destination(destination.publicKey().deriveAddress())
+ .signatureReward(testBridge.signatureReward())
+ .publicKey(testBridge.witnessKeyPair().publicKey())
+ .signature(attestationSignature)
+ .attestationRewardAccount(testBridge.witnessKeyPair().publicKey().deriveAddress())
+ .attestationSignerAccount(testBridge.witnessKeyPair().publicKey().deriveAddress())
+ .sequence(sourceAccountInfo.accountData().sequence())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
+ .lastLedgerSequence(sourceAccountInfo.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(4)))
+ .signingPublicKey(source.publicKey())
+ .build();
+
+ TransactionResult validatedTransaction = this.signSubmitAndWait(
+ transaction,
+ source,
+ XChainAddAccountCreateAttestation.class
+ );
+
+ assertThat(validatedTransaction.metadata()).isPresent();
+ TransactionMetadata metadata = validatedTransaction.metadata().get();
+ Optional maybeCreatedClaimId = metadata.affectedNodes().stream()
+ .filter(node -> node.ledgerEntryType().equals(MetaLedgerEntryType.XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID))
+ .findFirst();
+
+ assertThat(maybeCreatedClaimId).isNotEmpty();
+ AffectedNode createdClaimId = maybeCreatedClaimId.get();
+ assertThat(createdClaimId).isInstanceOf(CreatedNode.class);
+ MetaXChainOwnedCreateAccountClaimIdObject newFields =
+ ((CreatedNode) createdClaimId)
+ .newFields();
+ assertThat(newFields.account()).isNotEmpty().get().isEqualTo(testBridge.bridge().lockingChainDoor());
+ assertThat(newFields.xChainBridge()).isNotEmpty().get().isEqualTo(testBridge.bridge());
+ assertThat(newFields.xChainAccountCreateCount()).isNotEmpty().get().isEqualTo(XChainCount.of(UnsignedLong.ONE));
+ assertThat(newFields.xChainCreateAccountAttestations()).containsExactly(
+ ImmutableMetaXChainCreateAccountAttestation.builder()
+ .xChainCreateAccountProofSig(
+ ImmutableMetaXChainCreateAccountProofSig.builder()
+ .amount(transaction.amount())
+ .signatureReward(transaction.signatureReward())
+ .attestationRewardAccount(transaction.attestationRewardAccount())
+ .attestationSignerAccount(transaction.attestationSignerAccount())
+ .destination(transaction.destination())
+ .publicKey(testBridge.witnessKeyPair().publicKey())
+ .wasLockingChainSend(false)
+ .build()
+ )
+ .build()
+ );
+
+ XChainOwnedCreateAccountClaimIdObject claimIdObject = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ createdClaimId.ledgerIndex(), XChainOwnedCreateAccountClaimIdObject.class, LedgerSpecifier.VALIDATED
+ )
+ ).node();
+
+ assertThat(claimIdObject.account()).isEqualTo(testBridge.bridge().lockingChainDoor());
+ assertThat(claimIdObject.xChainAccountCreateCount()).isEqualTo(XChainCount.of(UnsignedLong.ONE));
+ assertThat(claimIdObject.xChainBridge()).isEqualTo(testBridge.bridge());
+ assertThat(claimIdObject.xChainCreateAccountAttestations()).containsExactly(
+ XChainCreateAccountAttestation.of(
+ XChainCreateAccountProofSig.builder()
+ .amount(transaction.amount())
+ .signatureReward(transaction.signatureReward().get())
+ .attestationRewardAccount(transaction.attestationRewardAccount())
+ .attestationSignerAccount(transaction.attestationSignerAccount())
+ .destination(transaction.destination())
+ .publicKey(testBridge.witnessKeyPair().publicKey())
+ .wasLockingChainSend(false)
+ .build()
+ )
+ );
+
+ // Create an attestation for witness 2 to sign
+ AttestationCreateAccount attestation2 = AttestationCreateAccount.builder()
+ .xChainBridge(testBridge.bridge())
+ .otherChainSource(otherChainSource.publicKey().deriveAddress())
+ .amount(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(300)))
+ .attestationRewardAccount(testBridge.witnessKeyPair2().publicKey().deriveAddress())
+ .wasLockingChainSend(false)
+ .destination(destination.publicKey().deriveAddress())
+ .signatureReward(testBridge.signatureReward())
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ONE))
+ .build();
+
+ // Witness 2 signs the attestation
+ Signature attestationSignature2 = signatureService.sign(testBridge.witnessKeyPair2().privateKey(), attestation2);
+
+ AccountInfoResult sourceAccountInfo2 = this.scanForResult(
+ () -> getValidatedAccountInfo(source.publicKey().deriveAddress())
+ );
+ // Add witness 2's attestation
+ XChainAddAccountCreateAttestation transaction2 = XChainAddAccountCreateAttestation.builder()
+ .account(source.publicKey().deriveAddress())
+ .xChainBridge(testBridge.bridge())
+ .otherChainSource(otherChainSource.publicKey().deriveAddress())
+ .amount(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(300)))
+ .wasLockingChainSend(false)
+ .xChainAccountCreateCount(XChainCount.of(UnsignedLong.ONE))
+ .destination(destination.publicKey().deriveAddress())
+ .signatureReward(testBridge.signatureReward())
+ .publicKey(testBridge.witnessKeyPair2().publicKey())
+ .signature(attestationSignature2)
+ .attestationRewardAccount(testBridge.witnessKeyPair2().publicKey().deriveAddress())
+ .attestationSignerAccount(testBridge.witnessKeyPair2().publicKey().deriveAddress())
+ .sequence(sourceAccountInfo2.accountData().sequence())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
+ .lastLedgerSequence(sourceAccountInfo2.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(4)))
+ .signingPublicKey(source.publicKey())
+ .build();
+
+ TransactionResult validatedTransaction2 = this.signSubmitAndWait(
+ transaction2,
+ source,
+ XChainAddAccountCreateAttestation.class
+ );
+
+ // The XChainOwnedCreateAccountClaimID should have gotten deleted
+ assertThat(validatedTransaction2.metadata()).isNotEmpty();
+ TransactionMetadata metadata2 = validatedTransaction2.metadata().get();
+ Optional maybeDeletedClaimId = metadata2.affectedNodes().stream()
+ .filter(node -> node.ledgerEntryType().equals(MetaLedgerEntryType.XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID))
+ .findFirst();
+
+ assertThat(maybeDeletedClaimId).isNotEmpty();
+ AffectedNode deletedClaimId = maybeDeletedClaimId.get();
+ assertThat(deletedClaimId).isInstanceOf(DeletedNode.class);
+
+ // And the destination account should exist now.
+ assertThatNoException().isThrownBy(() -> this.getValidatedAccountInfo(destination.publicKey().deriveAddress()));
+ }
+
+ @Test
+ void testXChainAddClaimAttestationXrpToXrpBridge() throws JsonRpcClientErrorException, JsonProcessingException {
+ KeyPair otherChainSource = Seed.ed25519Seed().deriveKeyPair();
+ KeyPair source = this.createRandomAccountEd25519();
+ XrpCurrencyAmount amount = XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(10));
+
+ AccountInfoResult sourceAccountInfo = this.scanForResult(
+ () -> this.getValidatedAccountInfo(source.publicKey().deriveAddress())
+ );
+ XrpCurrencyAmount fee = FeeUtils.computeNetworkFees(xrplClient.fee()).recommendedFee();
+ XChainOwnedClaimIdObject claimIdObject = createClaimId(
+ sourceAccountInfo,
+ fee,
+ source,
+ testBridge,
+ otherChainSource
+ );
+
+ XChainAddClaimAttestation addAttestation = addClaimAttestation(
+ otherChainSource,
+ amount,
+ source,
+ fee,
+ testBridge.bridge(),
+ testBridge.witnessKeyPair(),
+ false).transaction();
+
+ XChainOwnedClaimIdObject claimIdObjectAfterAdd = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ claimIdObject.index(),
+ XChainOwnedClaimIdObject.class,
+ LedgerSpecifier.VALIDATED
+ )).node();
+
+ assertThat(claimIdObjectAfterAdd.xChainClaimAttestations()).containsExactly(
+ XChainClaimAttestation.of(
+ XChainClaimProofSig.builder()
+ .amount(amount)
+ .publicKey(addAttestation.publicKey())
+ .wasLockingChainSend(false)
+ .attestationSignerAccount(addAttestation.attestationSignerAccount())
+ .attestationRewardAccount(addAttestation.attestationRewardAccount())
+ .destination(source.publicKey().deriveAddress())
+ .build()
+ )
+ );
+
+ XrpCurrencyAmount initialBalance = this.getValidatedAccountInfo(source.publicKey().deriveAddress())
+ .accountData().balance();
+
+ addClaimAttestation(
+ otherChainSource,
+ amount,
+ source,
+ fee,
+ testBridge.bridge(),
+ testBridge.witnessKeyPair2(),
+ false).transaction();
+
+ XrpCurrencyAmount finalBalance = this.getValidatedAccountInfo(source.publicKey().deriveAddress())
+ .accountData().balance();
+
+ assertThat(finalBalance).isEqualTo(
+ initialBalance.plus(amount).minus(testBridge.signatureReward())
+ );
+ }
+
+ @Test
+ void testAddClaimAttestationIouToIouBridge() throws JsonRpcClientErrorException, JsonProcessingException {
+ KeyPair lockingDoor = Seed.ed25519Seed().deriveKeyPair();
+ KeyPair issuer = Seed.ed25519Seed().deriveKeyPair();
+
+ KeyPair source = this.createRandomAccountEd25519();
+ XrpCurrencyAmount fee = FeeUtils.computeNetworkFees(xrplClient.fee()).recommendedFee();
+ enableRippling(source, fee);
+
+ KeyPair destination = this.createRandomAccountEd25519();
+
+ this.createTrustLine(
+ "USD",
+ "1000000000",
+ source,
+ destination,
+ fee
+ );
+
+ TestBridge iouBridge = setupBridge(
+ source,
+ XChainBridge.builder()
+ .lockingChainDoor(lockingDoor.publicKey().deriveAddress())
+ .lockingChainIssue(
+ Issue.builder()
+ .issuer(issuer.publicKey().deriveAddress())
+ .currency("USD")
+ .build()
+ )
+ .issuingChainDoor(source.publicKey().deriveAddress())
+ .issuingChainIssue(
+ Issue.builder()
+ .issuer(source.publicKey().deriveAddress())
+ .currency("USD")
+ .build()
+ )
+ .build(),
+ Optional.empty()
+ );
+
+ KeyPair otherChainSource = this.createRandomAccountEd25519();
+ IssuedCurrencyAmount amount = IssuedCurrencyAmount.builder()
+ .currency("USD")
+ .issuer(issuer.publicKey().deriveAddress())
+ .value("10")
+ .build();
+
+ AccountInfoResult sourceAccountInfo = this.scanForResult(
+ () -> this.getValidatedAccountInfo(source.publicKey().deriveAddress()));
+
+ XChainOwnedClaimIdObject claimIdObject = createClaimId(sourceAccountInfo, fee, source, iouBridge, otherChainSource);
+
+ XChainAddClaimAttestation addAttestation = addClaimAttestation(
+ otherChainSource,
+ amount,
+ destination,
+ fee,
+ iouBridge.bridge(),
+ iouBridge.witnessKeyPair(),
+ true
+ ).transaction();
+
+ XChainOwnedClaimIdObject claimIdObjectAfterAdd = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ claimIdObject.index(),
+ XChainOwnedClaimIdObject.class,
+ LedgerSpecifier.VALIDATED
+ )).node();
+
+ assertThat(claimIdObjectAfterAdd.xChainClaimAttestations()).containsExactly(
+ XChainClaimAttestation.of(
+ XChainClaimProofSig.builder()
+ .amount(amount)
+ .publicKey(addAttestation.publicKey())
+ .wasLockingChainSend(true)
+ .attestationSignerAccount(addAttestation.attestationSignerAccount())
+ .attestationRewardAccount(addAttestation.attestationRewardAccount())
+ .destination(destination.publicKey().deriveAddress())
+ .build()
+ )
+ );
+
+ BigDecimal initialBalance = new BigDecimal(this.getValidatedAccountLines(
+ destination.publicKey().deriveAddress(),
+ iouBridge.bridge().issuingChainIssue().issuer().get()
+ ).lines().get(0).balance());
+
+ addClaimAttestation(
+ otherChainSource,
+ amount,
+ destination,
+ fee,
+ iouBridge.bridge(),
+ iouBridge.witnessKeyPair2(),
+ true
+ ).transaction();
+
+ BigDecimal finalBalance = new BigDecimal(this.getValidatedAccountLines(
+ destination.publicKey().deriveAddress(),
+ iouBridge.bridge().issuingChainIssue().issuer().get()
+ ).lines().get(0).balance());
+
+ assertThat(finalBalance).isEqualTo(
+ initialBalance.add(new BigDecimal(amount.value()))
+ );
+ }
+
+ @Test
+ void testXChainClaim() throws JsonRpcClientErrorException, JsonProcessingException {
+ KeyPair destination = this.createRandomAccountEd25519();
+ KeyPair otherChainSource = Seed.ed25519Seed().deriveKeyPair();
+ XrpCurrencyAmount amount = XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(10));
+
+ AccountInfoResult destinationAccountInfo = this.scanForResult(
+ () -> this.getValidatedAccountInfo(destination.publicKey().deriveAddress())
+ );
+ XrpCurrencyAmount fee = FeeUtils.computeNetworkFees(xrplClient.fee()).recommendedFee();
+
+ XChainOwnedClaimIdObject claimIdObject = createClaimId(
+ destinationAccountInfo,
+ fee,
+ destination,
+ testBridge,
+ otherChainSource
+ );
+
+ XChainAddClaimAttestation addAttestation = addClaimAttestationForClaim(
+ otherChainSource,
+ amount,
+ fee,
+ testBridge.bridge(),
+ testBridge.witnessKeyPair(),
+ false
+ ).transaction();
+
+ XChainOwnedClaimIdObject claimIdObjectAfterAdd = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ claimIdObject.index(),
+ XChainOwnedClaimIdObject.class,
+ LedgerSpecifier.VALIDATED
+ )).node();
+
+ assertThat(claimIdObjectAfterAdd.xChainClaimAttestations()).containsExactly(
+ XChainClaimAttestation.of(
+ XChainClaimProofSig.builder()
+ .amount(amount)
+ .publicKey(addAttestation.publicKey())
+ .wasLockingChainSend(false)
+ .attestationSignerAccount(addAttestation.attestationSignerAccount())
+ .attestationRewardAccount(addAttestation.attestationRewardAccount())
+ .build()
+ )
+ );
+
+ XChainAddClaimAttestation addAttestation2 = addClaimAttestationForClaim(
+ otherChainSource,
+ amount,
+ fee,
+ testBridge.bridge(),
+ testBridge.witnessKeyPair2(),
+ false
+ ).transaction();
+
+ XChainOwnedClaimIdObject claimIdObjectAfterAdd2 = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ claimIdObject.index(),
+ XChainOwnedClaimIdObject.class,
+ LedgerSpecifier.VALIDATED
+ )).node();
+
+ assertThat(claimIdObjectAfterAdd2.xChainClaimAttestations()).containsExactlyInAnyOrder(
+ XChainClaimAttestation.of(
+ XChainClaimProofSig.builder()
+ .amount(amount)
+ .publicKey(addAttestation.publicKey())
+ .wasLockingChainSend(false)
+ .attestationSignerAccount(addAttestation.attestationSignerAccount())
+ .attestationRewardAccount(addAttestation.attestationRewardAccount())
+ .build()
+ ),
+ XChainClaimAttestation.of(
+ XChainClaimProofSig.builder()
+ .amount(amount)
+ .publicKey(addAttestation2.publicKey())
+ .wasLockingChainSend(false)
+ .attestationSignerAccount(addAttestation2.attestationSignerAccount())
+ .attestationRewardAccount(addAttestation2.attestationRewardAccount())
+ .build()
+ )
+ );
+
+ XrpCurrencyAmount initialBalance = this.getValidatedAccountInfo(destination.publicKey().deriveAddress())
+ .accountData()
+ .balance();
+ XChainClaim chainClaim = XChainClaim.builder()
+ .account(destinationAccountInfo.accountData().account())
+ .sequence(destinationAccountInfo.accountData().sequence().plus(UnsignedInteger.ONE))
+ .fee(fee)
+ .lastLedgerSequence(
+ destinationAccountInfo.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(10))
+ )
+ .signingPublicKey(destination.publicKey())
+ .xChainBridge(testBridge.bridge())
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .amount(amount)
+ .destination(destination.publicKey().deriveAddress())
+ .build();
+
+ this.signSubmitAndWait(chainClaim, destination, XChainClaim.class);
+
+ XrpCurrencyAmount finalBalance = this.getValidatedAccountInfo(destination.publicKey().deriveAddress())
+ .accountData()
+ .balance();
+
+ assertThat(finalBalance).isEqualTo(
+ initialBalance.plus(amount).minus(testBridge.signatureReward()).minus(fee)
+ );
+ }
+
+ @Test
+ void testXChainCommit() throws JsonRpcClientErrorException, JsonProcessingException {
+ KeyPair source = this.createRandomAccountEd25519();
+ KeyPair destination = this.createRandomAccountEd25519();
+ AccountInfoResult sourceAccountInfo = this.scanForResult(
+ () -> this.getValidatedAccountInfo(source.publicKey().deriveAddress()));
+ this.scanForResult(() -> this.getValidatedAccountInfo(destination.publicKey().deriveAddress()));
+
+ XrpCurrencyAmount initialDoorBalance = this.getValidatedAccountInfo(testBridge.bridge().lockingChainDoor())
+ .accountData()
+ .balance();
+
+ XrpCurrencyAmount initialSourceBalance = sourceAccountInfo.accountData().balance();
+ XrpCurrencyAmount amount = XrpCurrencyAmount.ofDrops(10000000);
+ XrpCurrencyAmount fee = FeeUtils.computeNetworkFees(xrplClient.fee()).recommendedFee();
+ XChainCommit chainCommit = XChainCommit.builder()
+ .account(source.publicKey().deriveAddress())
+ .sequence(sourceAccountInfo.accountData().sequence())
+ .fee(fee)
+ .lastLedgerSequence(sourceAccountInfo.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(4)))
+ .signingPublicKey(source.publicKey())
+ .xChainBridge(testBridge.bridge())
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .amount(amount)
+ .otherChainDestination(destination.publicKey().deriveAddress())
+ .build();
+
+ this.signSubmitAndWait(chainCommit, source, XChainCommit.class);
+
+ XrpCurrencyAmount finalDoorBalance = this.getValidatedAccountInfo(testBridge.bridge().lockingChainDoor())
+ .accountData()
+ .balance();
+
+ XrpCurrencyAmount finalSourceBalance = this.getValidatedAccountInfo(source.publicKey().deriveAddress())
+ .accountData()
+ .balance();
+
+ assertThat(finalDoorBalance).isEqualTo(
+ initialDoorBalance.plus(amount)
+ );
+
+ assertThat(finalSourceBalance).isEqualTo(
+ initialSourceBalance.minus(amount).minus(chainCommit.fee())
+ );
+ }
+
+ @Test
+ void testXChainModifyBridge() throws JsonRpcClientErrorException, JsonProcessingException {
+ KeyPair source = this.createRandomAccountEd25519();
+ AccountInfoResult sourceAccountInfo = this.scanForResult(
+ () -> this.getValidatedAccountInfo(source.publicKey().deriveAddress())
+ );
+
+ XrpCurrencyAmount fee = FeeUtils.computeNetworkFees(xrplClient.fee()).recommendedFee();
+
+ XChainCreateBridge createBridge = XChainCreateBridge.builder()
+ .account(sourceAccountInfo.accountData().account())
+ .sequence(sourceAccountInfo.accountData().sequence())
+ .fee(fee)
+ .lastLedgerSequence(sourceAccountInfo.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(4)))
+ .signingPublicKey(source.publicKey())
+ .xChainBridge(
+ XChainBridge.builder()
+ .lockingChainDoor(source.publicKey().deriveAddress())
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build()
+ )
+ .signatureReward(XrpCurrencyAmount.ofDrops(200))
+ .minAccountCreateAmount(XrpCurrencyAmount.ofDrops(10000000))
+ .build();
+
+ Hash256 bridgeId = this.signSubmitAndWait(createBridge, source, XChainCreateBridge.class)
+ .metadata()
+ .flatMap(transactionMetadata -> transactionMetadata.affectedNodes().stream()
+ .filter(node -> node.ledgerEntryType().equals(MetaLedgerEntryType.BRIDGE))
+ .findFirst()
+ ).map(AffectedNode::ledgerIndex)
+ .get();
+
+ BridgeObject bridgeObject = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ bridgeId,
+ BridgeObject.class,
+ LedgerSpecifier.VALIDATED
+ )
+ ).node();
+
+ assertThat(bridgeObject.signatureReward()).isEqualTo(XrpCurrencyAmount.ofDrops(200));
+ assertThat(bridgeObject.minAccountCreateAmount()).isNotEmpty().get().isEqualTo(XrpCurrencyAmount.ofDrops(10000000));
+
+ XChainModifyBridge modifySignerReward = XChainModifyBridge.builder()
+ .account(sourceAccountInfo.accountData().account())
+ .sequence(sourceAccountInfo.accountData().sequence().plus(UnsignedInteger.ONE))
+ .fee(fee)
+ .lastLedgerSequence(sourceAccountInfo.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(10)))
+ .signingPublicKey(source.publicKey())
+ .xChainBridge(bridgeObject.xChainBridge())
+ .signatureReward(XrpCurrencyAmount.ofDrops(300))
+ .build();
+
+ this.signSubmitAndWait(
+ modifySignerReward,
+ source,
+ XChainModifyBridge.class
+ );
+
+ BridgeObject bridgeAfterModify = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ bridgeId,
+ BridgeObject.class,
+ LedgerSpecifier.VALIDATED
+ )
+ ).node();
+
+ assertThat(bridgeAfterModify.signatureReward()).isEqualTo(XrpCurrencyAmount.ofDrops(300));
+ assertThat(bridgeAfterModify.minAccountCreateAmount()).isNotEmpty().get()
+ .isEqualTo(XrpCurrencyAmount.ofDrops(10000000));
+
+ XChainModifyBridge deleteMinCreateAmount = XChainModifyBridge.builder()
+ .account(sourceAccountInfo.accountData().account())
+ .sequence(sourceAccountInfo.accountData().sequence().plus(UnsignedInteger.valueOf(2)))
+ .fee(fee)
+ .lastLedgerSequence(sourceAccountInfo.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(14)))
+ .signingPublicKey(source.publicKey())
+ .xChainBridge(bridgeObject.xChainBridge())
+ .flags(XChainModifyBridgeFlags.CLEAR_ACCOUNT_CREATE_AMOUNT)
+ .build();
+
+ this.signSubmitAndWait(
+ deleteMinCreateAmount,
+ source,
+ XChainModifyBridge.class
+ );
+
+ bridgeAfterModify = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ bridgeId,
+ BridgeObject.class,
+ LedgerSpecifier.VALIDATED
+ )
+ ).node();
+
+ assertThat(bridgeAfterModify.signatureReward()).isEqualTo(XrpCurrencyAmount.ofDrops(300));
+ assertThat(bridgeAfterModify.minAccountCreateAmount()).isEmpty();
+ }
+
+ private XChainOwnedClaimIdObject createClaimId(
+ AccountInfoResult sourceAccountInfo,
+ XrpCurrencyAmount fee,
+ KeyPair source,
+ TestBridge bridge,
+ KeyPair otherChainSource
+ ) throws JsonRpcClientErrorException, JsonProcessingException {
+ XChainCreateClaimId chainCreateClaimId = XChainCreateClaimId.builder()
+ .account(sourceAccountInfo.accountData().account())
+ .sequence(sourceAccountInfo.accountData().sequence())
+ .fee(fee)
+ .signingPublicKey(source.publicKey())
+ .lastLedgerSequence(sourceAccountInfo.ledgerIndexSafe().plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue())
+ .xChainBridge(bridge.bridge())
+ .signatureReward(bridge.signatureReward())
+ .otherChainSource(otherChainSource.publicKey().deriveAddress())
+ .build();
+
+ TransactionResult validatedCreateClaimId = this.signSubmitAndWait(
+ chainCreateClaimId, source, XChainCreateClaimId.class
+ );
+
+ assertThat(validatedCreateClaimId.metadata()).isNotEmpty();
+ TransactionMetadata createClaimIdMetadata = validatedCreateClaimId.metadata().get();
+ Optional maybeAffectedNode = createClaimIdMetadata.affectedNodes().stream()
+ .filter(node -> node.ledgerEntryType().equals(MetaLedgerEntryType.XCHAIN_OWNED_CLAIM_ID))
+ .findFirst();
+ assertThat(maybeAffectedNode).isNotEmpty();
+
+ XChainOwnedClaimIdObject claimIdObject = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(maybeAffectedNode.get().ledgerIndex(),
+ XChainOwnedClaimIdObject.class, LedgerSpecifier.VALIDATED
+ )).node();
+
+ assertThat(claimIdObject.xChainBridge()).isEqualTo(bridge.bridge());
+ assertThat(claimIdObject.xChainClaimId()).isEqualTo(XChainClaimId.of(UnsignedLong.ONE));
+ assertThat(claimIdObject.otherChainSource()).isEqualTo(otherChainSource.publicKey().deriveAddress());
+ assertThat(claimIdObject.signatureReward()).isEqualTo(bridge.signatureReward());
+ assertThat(claimIdObject.xChainClaimAttestations()).isEmpty();
+
+ return claimIdObject;
+ }
+
+ private void enableRippling(KeyPair source, XrpCurrencyAmount fee)
+ throws JsonRpcClientErrorException, JsonProcessingException {
+ AccountInfoResult sourceAccountInfo = this.scanForResult(
+ () -> this.getValidatedAccountInfo(source.publicKey().deriveAddress())
+ );
+ AccountSet accountSet = AccountSet.builder()
+ .account(sourceAccountInfo.accountData().account())
+ .sequence(sourceAccountInfo.accountData().sequence())
+ .fee(fee)
+ .lastLedgerSequence(sourceAccountInfo.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(4)))
+ .signingPublicKey(source.publicKey())
+ .setFlag(AccountSetFlag.DEFAULT_RIPPLE)
+ .build();
+
+ this.signSubmitAndWait(accountSet, source, AccountSet.class);
+ }
+
+ private TransactionResult addClaimAttestation(
+ KeyPair otherChainSource,
+ CurrencyAmount amount,
+ KeyPair destination,
+ XrpCurrencyAmount fee,
+ XChainBridge bridge,
+ KeyPair witnessKeyPair,
+ boolean wasLockingChainSend
+ ) throws JsonRpcClientErrorException, JsonProcessingException {
+ AttestationClaim attestation = AttestationClaim.builder()
+ .xChainBridge(bridge)
+ .otherChainSource(otherChainSource.publicKey().deriveAddress())
+ .amount(amount)
+ .attestationRewardAccount(witnessKeyPair.publicKey().deriveAddress())
+ .wasLockingChainSend(wasLockingChainSend)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .destination(destination.publicKey().deriveAddress())
+ .build();
+
+ Signature attestationSignature = signatureService.sign(witnessKeyPair.privateKey(), attestation);
+
+ AccountInfoResult witnessAccountInfo = this.getValidatedAccountInfo(
+ witnessKeyPair.publicKey().deriveAddress()
+ );
+ XChainAddClaimAttestation addAttestation = XChainAddClaimAttestation.builder()
+ .account(witnessAccountInfo.accountData().account())
+ .sequence(witnessAccountInfo.accountData().sequence())
+ .fee(fee)
+ .lastLedgerSequence(witnessAccountInfo.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(4)))
+ .signingPublicKey(witnessKeyPair.publicKey())
+ .xChainBridge(bridge)
+ .otherChainSource(otherChainSource.publicKey().deriveAddress())
+ .amount(amount)
+ .wasLockingChainSend(wasLockingChainSend)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .destination(destination.publicKey().deriveAddress())
+ .publicKey(witnessKeyPair.publicKey())
+ .signature(attestationSignature)
+ .attestationSignerAccount(witnessAccountInfo.accountData().account())
+ .attestationRewardAccount(witnessAccountInfo.accountData().account())
+ .build();
+
+ return this.signSubmitAndWait(
+ addAttestation, witnessKeyPair, XChainAddClaimAttestation.class
+ );
+ }
+
+ private TransactionResult addClaimAttestationForClaim(
+ KeyPair otherChainSource,
+ CurrencyAmount amount,
+ XrpCurrencyAmount fee,
+ XChainBridge bridge,
+ KeyPair witnessKeyPair,
+ boolean wasLockingChainSend
+ ) throws JsonRpcClientErrorException, JsonProcessingException {
+ AttestationClaim attestation = AttestationClaim.builder()
+ .xChainBridge(bridge)
+ .otherChainSource(otherChainSource.publicKey().deriveAddress())
+ .amount(amount)
+ .attestationRewardAccount(witnessKeyPair.publicKey().deriveAddress())
+ .wasLockingChainSend(wasLockingChainSend)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .build();
+
+ Signature attestationSignature = signatureService.sign(witnessKeyPair.privateKey(), attestation);
+
+ AccountInfoResult witnessAccountInfo = this.getValidatedAccountInfo(
+ witnessKeyPair.publicKey().deriveAddress()
+ );
+ XChainAddClaimAttestation addAttestation = XChainAddClaimAttestation.builder()
+ .account(witnessAccountInfo.accountData().account())
+ .sequence(witnessAccountInfo.accountData().sequence())
+ .fee(fee)
+ .lastLedgerSequence(witnessAccountInfo.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(4)))
+ .signingPublicKey(witnessKeyPair.publicKey())
+ .xChainBridge(bridge)
+ .otherChainSource(otherChainSource.publicKey().deriveAddress())
+ .amount(amount)
+ .wasLockingChainSend(wasLockingChainSend)
+ .xChainClaimId(XChainClaimId.of(UnsignedLong.ONE))
+ .publicKey(witnessKeyPair.publicKey())
+ .signature(attestationSignature)
+ .attestationSignerAccount(witnessAccountInfo.accountData().account())
+ .attestationRewardAccount(witnessAccountInfo.accountData().account())
+ .build();
+
+ TransactionResult result = this.signSubmitAndWait(
+ addAttestation, witnessKeyPair, XChainAddClaimAttestation.class
+ );
+ logger.info(ObjectMapperFactory.create().writerWithDefaultPrettyPrinter().writeValueAsString(result));
+ return result;
+ }
+
+ private TestBridge setupBridge(
+ KeyPair doorKeyPair,
+ XChainBridge bridge,
+ Optional minAccountCreateAmount
+ ) throws JsonRpcClientErrorException, JsonProcessingException {
+ XrpCurrencyAmount signatureReward = XrpCurrencyAmount.ofDrops(200);
+ Address doorAddress = doorKeyPair.publicKey().deriveAddress();
+
+ AccountInfoResult doorAccountInfo = this.scanForResult(() -> this.getValidatedAccountInfo(doorAddress));
+ XChainCreateBridge createBridge = XChainCreateBridge.builder()
+ .account(doorAddress)
+ .xChainBridge(bridge)
+ .signatureReward(signatureReward)
+ .minAccountCreateAmount(minAccountCreateAmount)
+ .sequence(doorAccountInfo.accountData().sequence())
+ .fee(XrpCurrencyAmount.ofDrops(100))
+ .signingPublicKey(doorKeyPair.publicKey())
+ .lastLedgerSequence(doorAccountInfo.ledgerIndexSafe().plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue())
+ .build();
+
+ signSubmitAndWait(createBridge, doorKeyPair, XChainCreateBridge.class);
+
+ AccountObjectsResult doorObjects = this.getValidatedAccountObjects(doorAddress);
+ List bridgeObjects = doorObjects.accountObjects().stream()
+ .filter(object -> BridgeObject.class.isAssignableFrom(object.getClass()))
+ .collect(Collectors.toList());
+ assertThat(bridgeObjects).hasSize(1);
+ assertThat(bridgeObjects.get(0)).isInstanceOf(BridgeObject.class);
+ BridgeObject bridgeObject = (BridgeObject) bridgeObjects.get(0);
+ assertThat(bridgeObject.account()).isEqualTo(doorAddress);
+ assertThat(bridgeObject.minAccountCreateAmount()).isEqualTo(createBridge.minAccountCreateAmount());
+ assertThat(bridgeObject.signatureReward()).isEqualTo(signatureReward);
+ assertThat(bridgeObject.xChainAccountClaimCount()).isEqualTo(XChainCount.of(UnsignedLong.ZERO));
+ assertThat(bridgeObject.xChainAccountCreateCount()).isEqualTo(XChainCount.of(UnsignedLong.ZERO));
+ assertThat(bridgeObject.xChainBridge()).isEqualTo(bridge);
+ assertThat(bridgeObject.xChainClaimId()).isEqualTo(XChainClaimId.of(UnsignedLong.ZERO));
+
+ LedgerEntryResult bridgeLedgerEntry = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ bridgeObject.index(), BridgeObject.class, LedgerSpecifier.of(doorObjects.ledgerIndexSafe())
+ )
+ );
+
+ assertThat(bridgeLedgerEntry.node()).isEqualTo(bridgeObject);
+
+ LedgerEntryResult bridgeLedgerEntryTyped = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.bridge(
+ bridgeObject.account(), bridgeObject.xChainBridge(), LedgerSpecifier.of(doorObjects.ledgerIndexSafe())
+ )
+ );
+ assertThat(bridgeLedgerEntryTyped).isEqualTo(bridgeLedgerEntry);
+
+ KeyPair witnessKeyPair = this.createRandomAccountEd25519();
+ Address witnessAddress = witnessKeyPair.publicKey().deriveAddress();
+ KeyPair witnessKeyPair2 = this.createRandomAccountEd25519();
+ Address witnessAddress2 = witnessKeyPair2.publicKey().deriveAddress();
+ AccountInfoResult witnessAccountInfo = this.scanForResult(() -> this.getValidatedAccountInfo(witnessAddress));
+ SignerListSet signerListSet = SignerListSet.builder()
+ .account(doorAddress)
+ .sequence(doorAccountInfo.accountData().sequence().plus(UnsignedInteger.ONE))
+ .fee(XrpCurrencyAmount.ofDrops(100))
+ .signingPublicKey(doorKeyPair.publicKey())
+ .signerQuorum(UnsignedInteger.valueOf(2))
+ .addSignerEntries(
+ SignerEntryWrapper.of(
+ SignerEntry.builder()
+ .account(witnessAddress)
+ .signerWeight(UnsignedInteger.ONE)
+ .build()
+ ),
+ SignerEntryWrapper.of(
+ SignerEntry.builder()
+ .account(witnessAddress2)
+ .signerWeight(UnsignedInteger.ONE)
+ .build()
+ )
+ )
+ .lastLedgerSequence(witnessAccountInfo.ledgerIndexSafe().plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue())
+ .build();
+
+ this.signSubmitAndWait(signerListSet, doorKeyPair, SignerListSet.class);
+ return TestBridge.builder()
+ .bridgeId(bridgeObject.index())
+ .bridge(bridge)
+ .witnessKeyPair(witnessKeyPair)
+ .witnessKeyPair2(witnessKeyPair2)
+ .signatureReward(signatureReward)
+ .build();
+ }
+
+ private TestBridge setupXrpToXrpBridge() throws JsonRpcClientErrorException, JsonProcessingException {
+ KeyPair doorKeyPair = this.createRandomAccountEd25519();
+ return setupBridge(
+ doorKeyPair,
+ XChainBridge.builder()
+ .lockingChainDoor(doorKeyPair.publicKey().deriveAddress())
+ .lockingChainIssue(Issue.XRP)
+ .issuingChainDoor(AddressConstants.GENESIS_ACCOUNT)
+ .issuingChainIssue(Issue.XRP)
+ .build(),
+ Optional.of(XrpCurrencyAmount.ofDrops(10000000))
+ );
+ }
+
+
+ /**
+ * A cross chain bridge that can be used in integration tests.
+ */
+ @Value.Immutable
+ @JsonSerialize(as = ImmutableTestBridge.class)
+ @JsonDeserialize(as = ImmutableTestBridge.class)
+ interface TestBridge {
+
+ /**
+ * Construct a {@code TestBridge} builder.
+ *
+ * @return An {@link ImmutableTestBridge.Builder}.
+ */
+ static ImmutableTestBridge.Builder builder() {
+ return ImmutableTestBridge.builder();
+ }
+
+ /**
+ * The ID of the {@link BridgeObject}.
+ *
+ * @return A {@link Hash256}.
+ */
+ Hash256 bridgeId();
+
+ /**
+ * The {@link XChainBridge} spec.
+ *
+ * @return An {@link XChainBridge}.
+ */
+ XChainBridge bridge();
+
+ /**
+ * The {@link KeyPair} of the first witness.
+ *
+ * @return A {@link KeyPair}.
+ */
+ KeyPair witnessKeyPair();
+
+ /**
+ * The {@link KeyPair} of the second witness.
+ *
+ * @return A {@link KeyPair}.
+ */
+ KeyPair witnessKeyPair2();
+
+ /**
+ * The signature reward of the bridge.
+ *
+ * @return An {@link XrpCurrencyAmount}.
+ */
+ XrpCurrencyAmount signatureReward();
+
+ }
+}
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/environment/RippledContainer.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/environment/RippledContainer.java
index d5f5484b9..8ed24e93a 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/environment/RippledContainer.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/environment/RippledContainer.java
@@ -69,7 +69,7 @@ public class RippledContainer {
* No-args constructor.
*/
public RippledContainer() {
- rippledContainer = new GenericContainer("xrpllabsofficial/xrpld:latest")
+ rippledContainer = new GenericContainer("rippleci/rippled:2.0.0-b4")
.withCreateContainerCmdModifier((Consumer) (cmd) ->
cmd.withEntrypoint("/opt/ripple/bin/rippled"))
.withCommand("-a --start --conf /config/rippled.cfg")
diff --git a/xrpl4j-integration-tests/src/test/resources/rippled/rippled.cfg b/xrpl4j-integration-tests/src/test/resources/rippled/rippled.cfg
index 8b9565494..8f909bae9 100644
--- a/xrpl4j-integration-tests/src/test/resources/rippled/rippled.cfg
+++ b/xrpl4j-integration-tests/src/test/resources/rippled/rippled.cfg
@@ -1,701 +1,11 @@
-#-------------------------------------------------------------------------------
-#
-#
-#-------------------------------------------------------------------------------
-#
-# Contents
-#
-# 1. Server
-#
-# 2. Peer Protocol
-#
-# 3. Ripple Protocol
-#
-# 4. HTTPS Client
-#
-# 5. Database
-#
-# 6. Diagnostics
-#
-# 7. Voting
-#
-# 8. Misc Settings
-#
-# 9. Example Settings
-#
-#-------------------------------------------------------------------------------
-#
-# Purpose
-#
-# This file documents and provides examples of all rippled server process
-# configuration options. When the rippled server instance is launched, it
-# looks for a file with the following name:
-#
-# rippled.cfg
-#
-# For more information on where the rippled server instance searches for the
-# file, visit:
-#
-# https://developers.ripple.com/commandline-usage.html#generic-options
-#
-# This file should be named rippled.cfg. This file is UTF-8 with DOS, UNIX,
-# or Mac style end of lines. Blank lines and lines beginning with '#' are
-# ignored. Undefined sections are reserved. No escapes are currently defined.
-#
-# Notation
-#
-# In this document a simple BNF notation is used. Angle brackets denote
-# required elements, square brackets denote optional elements, and single
-# quotes indicate string literals. A vertical bar separating 1 or more
-# elements is a logical "or"; any one of the elements may be chosen.
-# Parentheses are notational only, and used to group elements; they are not
-# part of the syntax unless they appear in quotes. White space may always
-# appear between elements, it has no effect on values.
-#
-# A required identifier
-# '=' The equals sign character
-# | Logical "or"
-# ( ) Used for grouping
-#
-#
-# An identifier is a string of upper or lower case letters, digits, or
-# underscores subject to the requirement that the first character of an
-# identifier must be a letter. Identifiers are not case sensitive (but
-# values may be).
-#
-# Some configuration sections contain key/value pairs. A line containing
-# a key/value pair has this syntax:
-#
-# '='
-#
-# Depending on the section and key, different value types are possible:
-#
-# A signed integer
-# An unsigned integer
-# A boolean. 1 = true/yes/on, 0 = false/no/off.
-#
-# Consult the documentation on the key in question to determine the possible
-# value types.
-#
-#
-#
-#-------------------------------------------------------------------------------
-#
-# 1. Server
-#
-#----------
-#
-#
-#
-# rippled offers various server protocols to clients making inbound
-# connections. The listening ports rippled uses are "universal" ports
-# which may be configured to handshake in one or more of the available
-# supported protocols. These universal ports simplify administration:
-# A single open port can be used for multiple protocols.
-#
-# NOTE At least one server port must be defined in order
-# to accept incoming network connections.
-#
-#
-# [server]
-#
-# A list of port names and key/value pairs. A port name must start with a
-# letter and contain only letters and numbers. The name is not case-sensitive.
-# For each name in this list, rippled will look for a configuration file
-# section with the same name and use it to create a listening port. The
-# name is informational only; the choice of name does not affect the function
-# of the listening port.
-#
-# Key/value pairs specified in this section are optional, and apply to all
-# listening ports unless the port overrides the value in its section. They
-# may be considered default values.
-#
-# Suggestion:
-#
-# To avoid a conflict with port names and future configuration sections,
-# we recommend prepending "port_" to the port name. This prefix is not
-# required, but suggested.
-#
-# This example defines two ports with different port numbers and settings:
-#
-# [server]
-# port_public
-# port_private
-# port = 80
-#
-# [port_public]
-# ip = 0.0.0.0
-# port = 443
-# protocol = peer,https
-#
-# [port_private]
-# ip = 0.0.0.0
-# protocol = http
-#
-# When rippled is used as a command line client (for example, issuing a
-# server stop command), the first port advertising the http or https
-# protocol will be used to make the connection.
-#
-#
-#
-# []
-#
-# A series of key/value pairs that define the settings for the port with
-# the corresponding name. These keys are possible:
-#
-# ip =
-#
-# Required. Determines the IP address of the network interface to bind
-# to. To bind to all available IPv4 interfaces, use 0.0.0.0
-# To binding to all IPv4 and IPv6 interfaces, use ::
-#
-# NOTE if the ip value is ::, then any incoming IPv4 connections will
-# be made as mapped IPv4 addresses.
-#
-# port =
-#
-# Required. Sets the port number to use for this port.
-#
-# protocol = [ http, https, peer ]
-#
-# Required. A comma-separated list of protocols to support:
-#
-# http JSON-RPC over HTTP
-# https JSON-RPC over HTTPS
-# ws Websockets
-# wss Secure Websockets
-# peer Peer Protocol
-#
-# Restrictions:
-#
-# Only one port may be configured to support the peer protocol.
-# A port cannot have websocket and non websocket protocols at the
-# same time. It is possible have both Websockets and Secure Websockets
-# together in one port.
-#
-# NOTE If no ports support the peer protocol, rippled cannot
-# receive incoming peer connections or become a superpeer.
-#
-# limit =
-#
-# Optional. An integer value that will limit the number of connected
-# clients that the port will accept. Once the limit is reached, new
-# connections will be refused until other clients disconnect.
-# Omit or set to 0 to allow unlimited numbers of clients.
-#
-# user =
-# password =
-#
-# When set, these credentials will be required on HTTP/S requests.
-# The credentials must be provided using HTTP's Basic Authentication
-# headers. If either or both fields are empty, then no credentials are
-# required. IP address restrictions, if any, will be checked in addition
-# to the credentials specified here.
-#
-# When acting in the client role, rippled will supply these credentials
-# using HTTP's Basic Authentication headers when making outbound HTTP/S
-# requests.
-#
-# admin = [ IP, IP, IP, ... ]
-#
-# A comma-separated list of IP addresses.
-#
-# When set, grants administrative command access to the specified IP
-# addresses. These commands may be issued over http, https, ws, or wss
-# if configured on the port. If not provided, the default is to not allow
-# administrative commands.
-#
-# NOTE A common configuration value for the admin field is "localhost".
-# If you are listening on all IPv4/IPv6 addresses by specifing
-# ip = :: then you can use admin = ::ffff:0.0.0.0,::1 to allow
-# administrative access from both IPv4 and IPv6 localhost
-# connections.
-#
-# *SECURITY WARNING*
-# 0.0.0.0 or :: may be used to allow access from any IP address. It must
-# be the only address specified and cannot be combined with other IPs.
-# Use of this address can compromise server security, please consider its
-# use carefully.
-#
-# admin_user =
-# admin_password =
-#
-# When set, clients must provide these credentials in the submitted
-# JSON for any administrative command requests submitted to the HTTP/S,
-# WS, or WSS protocol interfaces. If administrative commands are
-# disabled for a port, these credentials have no effect.
-#
-# When acting in the client role, rippled will supply these credentials
-# in the submitted JSON for any administrative command requests when
-# invoking JSON-RPC commands on remote servers.
-#
-# secure_gateway = [ IP, IP, IP, ... ]
-#
-# A comma-separated list of IP addresses.
-#
-# When set, allows the specified IP addresses to pass HTTP headers
-# containing username and remote IP address for each session. If a
-# non-empty username is passed in this way, then resource controls
-# such as often resulting in "tooBusy" errors will be lifted. However,
-# administrative RPC commands such as "stop" will not be allowed.
-# The HTTP headers that secure_gateway hosts can set are X-User and
-# X-Forwarded-For. Only the X-User header affects resource controls.
-# However, both header values are logged to help identify user activity.
-# If no X-User header is passed, or if its value is empty, then
-# resource controls will default to those for non-administrative users.
-#
-# The secure_gateway IP addresses are intended to represent
-# proxies. Since rippled trusts these hosts, they must be
-# responsible for properly authenticating the remote user.
-#
-# The same IP address cannot be used in both "admin" and "secure_gateway"
-# lists for the same port. In this case, rippled will abort with an error
-# message to the console shortly after startup
-#
-# ssl_key =
-# ssl_cert =
-# ssl_chain =
-#
-# Use the specified files when configuring SSL on the port.
-#
-# NOTE If no files are specified and secure protocols are selected,
-# rippled will generate an internal self-signed certificate.
-#
-# The files have these meanings:
-#
-# ssl_key
-#
-# Specifies the filename holding the SSL key in PEM format.
-#
-# ssl_cert
-#
-# Specifies the path to the SSL certificate file in PEM format.
-# This is not needed if the chain includes it.
-#
-# ssl_chain
-#
-# If you need a certificate chain, specify the path to the
-# certificate chain here. The chain may include the end certificate.
-#
-# ssl_ciphers =
-#
-# Control the ciphers which the server will support over SSL on the port,
-# specified using the OpenSSL "cipher list format".
-#
-# NOTE If unspecified, rippled will automatically configure a modern
-# cipher suite. This default suite should be widely supported.
-#
-# You should not modify this string unless you have a specific
-# reason and cryptographic expertise. Incorrect modification may
-# keep rippled from connecting to other instances of rippled or
-# prevent RPC and WebSocket clients from connecting.
-#
-# send_queue_limit = [1..65535]
-#
-# A Websocket will disconnect when its send queue exceeds this limit.
-# The default is 100. A larger value may help with erratic disconnects but
-# may adversely affect server performance.
-#
-# WebSocket permessage-deflate extension options
-#
-# These settings configure the optional permessage-deflate extension
-# options and may appear on any port configuration entry. They are meaningful
-# only to ports which have enabled a WebSocket protocol.
-#
-# permessage_deflate =
-#
-# Determines if permessage_deflate extension negotiations are enabled.
-# When enabled, clients may request the extension and the server will
-# offer the enabled extension in response.
-#
-# client_max_window_bits = [9..15]
-# server_max_window_bits = [9..15]
-# client_no_context_takeover =
-# server_no_context_takeover =
-#
-# These optional settings control options related to the permessage-deflate
-# extension negotiation. For precise definitions of these fields please see
-# the RFC 7692, "Compression Extensions for WebSocket":
-# https://tools.ietf.org/html/rfc7692
-#
-# compress_level = [0..9]
-#
-# When set, determines the amount of compression attempted, where 0 is
-# the least amount and 9 is the most amount. Higher levels require more
-# CPU resources. Levels 1 through 3 use a fast compression algorithm,
-# while levels 4 through 9 use a more compact algorithm which uses more
-# CPU resources. If unspecified, a default of 3 is used.
-#
-# memory_level = [1..9]
-#
-# When set, determines the relative amount of memory used to hold
-# intermediate compression data. Higher numbers can give better compression
-# ratios at the cost of higher memory and CPU resources.
-#
-# [rpc_startup]
-#
-# Specify a list of RPC commands to run at startup.
-#
-# Examples:
-# { "command" : "server_info" }
-# { "command" : "log_level", "partition" : "ripplecalc", "severity" : "trace" }
-#
-#
-#
-# [websocket_ping_frequency]
-#
-#
-#
-# The amount of time to wait in seconds, before sending a websocket 'ping'
-# message. Ping messages are used to determine if the remote end of the
-# connection is no longer available.
-#
-#
-#
-#-------------------------------------------------------------------------------
-#
-# 2. Peer Protocol
-#
-#-----------------
-#
-# These settings control security and access attributes of the Peer to Peer
-# server section of the rippled process. Peer Protocol implements the
-# Ripple Payment protocol. It is over peer connections that transactions
-# and validations are passed from to machine to machine, to determine the
-# contents of validated ledgers.
-#
-#
-#
-# [ips]
-#
-# List of hostnames or ips where the Ripple protocol is served. A default
-# starter list is included in the code and used if no other hostnames are
-# available.
-#
-# One address or domain name per line is allowed. A port may must be
-# specified after adding a space to the address. The ordering of entries
-# does not generally matter.
-#
-# The default list of entries is:
-# - r.ripple.com 51235
-# - zaphod.alloy.ee 51235
-# - sahyadri.isrdc.in 51235
-#
-# Examples:
-#
-# [ips]
-# 192.168.0.1
-# 192.168.0.1 2459
-# r.ripple.com 51235
-#
-#
-# [ips_fixed]
-#
-# List of IP addresses or hostnames to which rippled should always attempt to
-# maintain peer connections with. This is useful for manually forming private
-# networks, for example to configure a validation server that connects to the
-# Ripple network through a public-facing server, or for building a set
-# of cluster peers.
-#
-# One address or domain names per line is allowed. A port must be specified
-# after adding a space to the address.
-#
-#
-#
-# [peer_private]
-#
-# 0 or 1.
-#
-# 0: Request peers to broadcast your address. Normal outbound peer connections [default]
-# 1: Request peers not broadcast your address. Only connect to configured peers.
-#
-#
-#
-# [peers_max]
-#
-# The largest number of desired peer connections (incoming or outgoing).
-# Cluster and fixed peers do not count towards this total. There are
-# implementation-defined lower limits imposed on this value for security
-# purposes.
-#
-#
-#
-# [node_seed]
-#
-# This is used for clustering. To force a particular node seed or key, the
-# key can be set here. The format is the same as the validation_seed field.
-# To obtain a validation seed, use the validation_create command.
-#
-# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE
-# shfArahZT9Q9ckTf3s1psJ7C7qzVN
-#
-#
-#
-# [cluster_nodes]
-#
-# To extend full trust to other nodes, place their node public keys here.
-# Generally, you should only do this for nodes under common administration.
-# Node public keys start with an 'n'. To give a node a name for identification
-# place a space after the public key and then the name.
-#
-#
-#
-# [sntp_servers]
-#
-# IP address or domain of NTP servers to use for time synchronization.
-#
-# These NTP servers are suitable for rippled servers located in the United
-# States:
-# time.windows.com
-# time.apple.com
-# time.nist.gov
-# pool.ntp.org
-#
-#
-#
-# [overlay]
-#
-# Controls settings related to the peer to peer overlay.
-#
-# A set of key/value pair parameters to configure the overlay.
-#
-# public_ip =
-#
-# If the server has a known, fixed public IPv4 address,
-# specify that IP address here in dotted decimal notation.
-# Peers will use this information to reject attempt to proxy
-# connections to or from this server.
-#
-# ip_limit =
-#
-# The maximum number of incoming peer connections allowed by a single
-# IP that isn't classified as "private" in RFC1918. The implementation
-# imposes some hard and soft upper limits on this value to prevent a
-# single host from consuming all inbound slots. If the value is not
-# present the server will autoconfigure an appropriate limit.
-#
-#
-#
-# [transaction_queue] EXPERIMENTAL
-#
-# This section is EXPERIMENTAL, and should not be
-# present for production configuration settings.
-#
-# A set of key/value pair parameters to tune the performance of the
-# transaction queue.
-#
-# ledgers_in_queue =
-#
-# The queue will be limited to this of average ledgers'
-# worth of transactions. If the queue fills up, the transactions
-# with the lowest fee levels will be dropped from the queue any
-# time a transaction with a higher fee level is added.
-# Default: 20.
-#
-# minimum_queue_size =
-#
-# The queue will always be able to hold at least this of
-# transactions, regardless of recent ledger sizes or the value of
-# ledgers_in_queue. Default: 2000.
-#
-# retry_sequence_percent =
-#
-# If a client replaces a transaction in the queue (same sequence
-# number as a transaction already in the queue), the new
-# transaction's fee must be more than percent higher
-# than the original transaction's fee, or meet the current open
-# ledger fee to be considered. Default: 25.
-#
-# multi_txn_percent =
-#
-# If a client submits multiple transactions (different sequence
-# numbers), later transactions must pay a fee at least
-# percent higher than the transaction with the previous sequence
-# number.
-# Default: -90.
-#
-# minimum_escalation_multiplier =
-#
-# At ledger close time, the median fee level of the transactions
-# in that ledger is used as a multiplier in escalation
-# calculations of the next ledger. This minimum value ensures that
-# the escalation is significant. Default: 500.
-#
-# minimum_txn_in_ledger =
-#
-# Minimum number of transactions that must be allowed into the
-# ledger at the minimum required fee before the required fee
-# escalates. Default: 5.
-#
-# minimum_txn_in_ledger_standalone =
-#
-# Like minimum_txn_in_ledger when rippled is running in standalone
-# mode. Default: 1000.
-#
-# target_txn_in_ledger =
-#
-# Number of transactions allowed into the ledger at the minimum
-# required fee that the queue will "work toward" as long as
-# consensus stays healthy. The limit will grow quickly until it
-# reaches or exceeds this number. After that the limit may still
-# change, but will stay above the target. If consensus is not
-# healthy, the limit will be clamped to this value or lower.
-# Default: 50.
-#
-# maximum_txn_in_ledger =
-#
-# (Optional) Maximum number of transactions that will be allowed
-# into the ledger at the minimum required fee before the required
-# fee escalates. Default: no maximum.
-#
-# normal_consensus_increase_percent =
-#
-# (Optional) When the ledger has more transactions than "expected",
-# and performance is humming along nicely, the expected ledger size
-# is updated to the previous ledger size plus this percentage.
-# Default: 20
-#
-# slow_consensus_decrease_percent =
-#
-# (Optional) When consensus takes longer than appropriate, the
-# expected ledger size is updated to the minimum of the previous
-# ledger size or the "expected" ledger size minus this percentage.
-# Default: 50
-#
-# maximum_txn_per_account =
-#
-# Maximum number of transactions that one account can have in the
-# queue at any given time. Default: 10.
-#
-# minimum_last_ledger_buffer =
-#
-# If a transaction has a LastLedgerSequence, it must be at least
-# this much larger than the current open ledger sequence number.
-# Default: 2.
-#
-# zero_basefee_transaction_feelevel =
-#
-# So we don't deal with infinite fee levels, treat any transaction
-# with a 0 base fee (ie. SetRegularKey password recovery) as
-# having this fee level.
-# Default: 256000.
-#
-#
-#-------------------------------------------------------------------------------
-#
-# 3. Ripple Protocol
-#
-#-------------------
-#
-# These settings affect the behavior of the server instance with respect
-# to Ripple payment protocol level activities such as validating and
-# closing ledgers or adjusting fees in response to server overloads.
-#
-#
-#
-# [node_size]
-#
-# Tunes the servers based on the expected load and available memory. Legal
-# sizes are "tiny", "small", "medium", "large", and "huge". We recommend
-# you start at the default and raise the setting if you have extra memory.
-# The default is "tiny".
-#
-#
-#
-# [ledger_history]
-#
-# The number of past ledgers to acquire on server startup and the minimum to
-# maintain while running.
-#
-# To serve clients, servers need historical ledger data. Servers that don't
-# need to serve clients can set this to "none". Servers that want complete
-# history can set this to "full".
-#
-# This must be less than or equal to online_delete (if online_delete is used)
-#
-# The default is: 256
-#
-#
-#
-# [fetch_depth]
-#
-# The number of past ledgers to serve to other peers that request historical
-# ledger data (or "full" for no limit).
-#
-# Servers that require low latency and high local performance may wish to
-# restrict the historical ledgers they are willing to serve. Setting this
-# below 32 can harm network stability as servers require easy access to
-# recent history to stay in sync. Values below 128 are not recommended.
-#
-# The default is: full
-#
-#
-#
-# [validation_seed]
-#
-# To perform validation, this section should contain either a validation seed
-# or key. The validation seed is used to generate the validation
-# public/private key pair. To obtain a validation seed, use the
-# validation_create command.
-#
-# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE
-# shfArahZT9Q9ckTf3s1psJ7C7qzVN
-#
-#
-#
-# [validator_token]
-#
-# This is an alternative to [validation_seed] that allows rippled to perform
-# validation without having to store the validator keys on the network
-# connected server. The field should contain a single token in the form of a
-# base64-encoded blob.
-# An external tool is available for generating validator keys and tokens.
-#
-#
-#
-# [validator_key_revocation]
-#
-# If a validator's secret key has been compromised, a revocation must be
-# generated and added to this field. The revocation notifies peers that it is
-# no longer safe to trust the revoked key. The field should contain a single
-# revocation in the form of a base64-encoded blob.
-# An external tool is available for generating and revoking validator keys.
-#
-#
-#
-# [validators_file]
-#
-# Path or name of a file that determines the nodes to always accept as validators.
-#
-# The contents of the file should include a [validators] and/or
-# [validator_list_sites] and [validator_list_keys] entries.
-# [validators] should be followed by a list of validation public keys of
-# nodes, one per line.
-# [validator_list_sites] should be followed by a list of URIs each serving a
-# list of recommended validators.
-# [validator_list_keys] should be followed by a list of keys belonging to
-# trusted validator list publishers. Validator lists fetched from configured
-# sites will only be considered if the list is accompanied by a valid
-# signature from a trusted publisher key.
-#
-# Specify the file by its name or path.
-# Unless an absolute path is specified, it will be considered relative to
-# the folder in which the rippled.cfg file is located.
-#
-# Examples:
-# /home/ripple/validators.txt
-# C:/home/ripple/validators.txt
-#
-# Example content:
-# [validators]
-# n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
-# n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
-# n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
-# n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
-# n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
-#
-#
-#
+[server]
+port_rpc_admin_local
+port_peer
+port_ws_admin_local
+port_ws_public
+#ssl_key = /etc/ssl/private/server.key
+#ssl_cert = /etc/ssl/certs/server.crt
+
[path_search]
10
# When searching for paths, the default search aggressiveness. This can take
@@ -716,453 +26,6 @@
#
[path_search_old]
10
-#
-# For clients that use the legacy path finding interfaces, the search
-# aggressiveness to use. The default is 7.
-#
-#
-#
-# [fee_default]
-#
-# Sets the base cost of a transaction in drops. Used when the server has
-# no other source of fee information, such as signing transactions offline.
-#
-#
-#
-# [workers]
-#
-# Configures the number of threads for processing work submitted by peers
-# and clients. If not specified, then the value is automatically determined
-# by factors including the number of system processors and whether this
-# node is a validator.
-#
-#
-#
-[network_id]
-255
-#
-# Specify the network which this server is configured to connect to and
-# track. If set, the server will not establish connections with servers
-# that are explicitly configured to track another network.
-#
-# Network identifiers are usually unsigned integers in the range 0 to
-# 4294967295 inclusive. The server also maps the following well-known
-# names to the corresponding numerical identifier:
-#
-# main -> 0
-# testnet -> 1
-#
-# If this value is not specified the server is not explicitly configured
-# to track a particular network.
-#
-#
-#-------------------------------------------------------------------------------
-#
-# 4. HTTPS Client
-#
-#----------------
-#
-# The rippled server instance uses HTTPS GET requests in a variety of
-# circumstances, including but not limited to contacting trusted domains to
-# fetch information such as mapping an email address to a Ripple Payment
-# Network address.
-#
-# [ssl_verify]
-#
-# 0 or 1.
-#
-# 0. HTTPS client connections will not verify certificates.
-# 1. Certificates will be checked for HTTPS client connections.
-#
-# If not specified, this parameter defaults to 1.
-#
-#
-#
-# [ssl_verify_file]
-#
-#
-#
-# A file system path leading to the certificate verification file for
-# HTTPS client requests.
-#
-#
-#
-# [ssl_verify_dir]
-#
-#
-#
-#
-# A file system path leading to a file or directory containing the root
-# certificates that the server will accept for verifying HTTP servers.
-# Used only for outbound HTTPS client connections.
-#
-#
-#
-#-------------------------------------------------------------------------------
-#
-# 5. Database
-#
-#------------
-#
-# rippled creates 4 SQLite database to hold bookkeeping information
-# about transactions, local credentials, and various other things.
-# It also creates the NodeDB, which holds all the objects that
-# make up the current and historical ledgers.
-#
-# The size of the NodeDB grows in proportion to the amount of new data and the
-# amount of historical data (a configurable setting) so the performance of the
-# underlying storage media where the NodeDB is placed can significantly affect
-# the performance of the server.
-#
-# Partial pathnames will be considered relative to the location of
-# the rippled.cfg file.
-#
-# [node_db] Settings for the Node Database (required)
-#
-# Format (without spaces):
-# One or more lines of case-insensitive key / value pairs:
-# '='
-# ...
-#
-# Example:
-# type=nudb
-# path=db/nudb
-#
-# The "type" field must be present and controls the choice of backend:
-#
-# type = NuDB
-#
-# NuDB is a high-performance database written by Ripple Labs and optimized
-# for rippled and solid-state drives.
-#
-# NuDB maintains its high speed regardless of the amount of history
-# stored. Online delete may be selected, but is not required. NuDB is
-# available on all platforms that rippled runs on.
-#
-# type = RocksDB
-#
-# RocksDB is an open-source, general-purpose key/value store - see
-# http://rocksdb.org/ for more details.
-#
-# RocksDB is an alternative backend for systems that don't use solid-state
-# drives. Because RocksDB's performance degrades as it stores more data,
-# keeping full history is not advised, and using online delete is
-# recommended.
-#
-# Required keys:
-# path Location to store the database (all types)
-#
-# Optional keys:
-#
-# These keys are possible for any type of backend:
-#
-# online_delete Minimum value of 256. Enable automatic purging
-# of older ledger information. Maintain at least this
-# number of ledger records online. Must be greater
-# than or equal to ledger_history.
-#
-# advisory_delete 0 for disabled, 1 for enabled. If set, then
-# require administrative RPC call "can_delete"
-# to enable online deletion of ledger records.
-#
-# earliest_seq The default is 32570 to match the XRP ledger
-# network's earliest allowed sequence. Alternate
-# networks may set this value. Minimum value of 1.
-#
-# Notes:
-# The 'node_db' entry configures the primary, persistent storage.
-#
-# The 'import_db' is used with the '--import' command line option to
-# migrate the specified database into the current database given
-# in the [node_db] section.
-#
-# [import_db] Settings for performing a one-time import (optional)
-# [database_path] Path to the book-keeping databases.
-#
-# [shard_db] Settings for the Shard Database (optional)
-#
-# Format (without spaces):
-# One or more lines of case-insensitive key / value pairs:
-# '='
-# ...
-#
-# Example:
-# path=db/shards/nudb
-#
-# Required keys:
-# path Location to store the database
-#
-# max_size_gb Maximum disk space the database will utilize (in gigabytes)
-#
-#
-# There are 4 bookkeeping SQLite database that the server creates and
-# maintains. If you omit this configuration setting, it will default to
-# creating a directory called "db" located in the same place as your
-# rippled.cfg file. Partial pathnames will be considered relative to
-# the location of the rippled executable.
-#
-#
-#
-#
-#-------------------------------------------------------------------------------
-#
-# 6. Diagnostics
-#
-#---------------
-#
-# These settings are designed to help server administrators diagnose
-# problems, and obtain detailed information about the activities being
-# performed by the rippled process.
-#
-#
-#
-# [debug_logfile]
-#
-# Specifies where a debug logfile is kept. By default, no debug log is kept.
-# Unless absolute, the path is relative the directory containing this file.
-#
-# Example: debug.log
-#
-#
-#
-# [insight]
-#
-# Configuration parameters for the Beast. Insight stats collection module.
-#
-# Insight is a module that collects information from the areas of rippled
-# that have instrumentation. The configuration parameters control where the
-# collection metrics are sent. The parameters are expressed as key = value
-# pairs with no white space. The main parameter is the choice of server:
-#
-# "server"
-#
-# Choice of server to send metrics to. Currently the only choice is
-# "statsd" which sends UDP packets to a StatsD daemon, which must be
-# running while rippled is running. More information on StatsD is
-# available here:
-# https://github.com/b/statsd_spec
-#
-# When server=statsd, these additional keys are used:
-#
-# "address" The UDP address and port of the listening StatsD server,
-# in the format, n.n.n.n:port.
-#
-# "prefix" A string prepended to each collected metric. This is used
-# to distinguish between different running instances of rippled.
-#
-# If this section is missing, or the server type is unspecified or unknown,
-# statistics are not collected or reported.
-#
-# Example:
-#
-# [insight]
-# server=statsd
-# address=192.168.0.95:4201
-# prefix=my_validator
-#
-# [perf]
-#
-# Configuration of performance logging. If enabled, write Json-formatted
-# performance-oriented data periodically to a distinct log file.
-#
-# "perf_log" A string specifying the pathname of the performance log
-# file. A relative pathname will log relative to the
-# configuration directory. Required to enable
-# performance logging.
-#
-# "log_interval" Integer value for number of seconds between writing
-# to performance log. Default 1.
-#
-# Example:
-# [perf]
-# perf_log=/var/log/rippled/perf.log
-# log_interval=2
-#
-#-------------------------------------------------------------------------------
-#
-# 7. Voting
-#
-#----------
-#
-# The vote settings configure settings for the entire Ripple network.
-# While a single instance of rippled cannot unilaterally enforce network-wide
-# settings, these choices become part of the instance's vote during the
-# consensus process for each voting ledger.
-#
-# [voting]
-#
-# A set of key/value pair parameters used during voting ledgers.
-#
-# reference_fee =
-#
-# The cost of the reference transaction fee, specified in drops.
-# The reference transaction is the simplest form of transaction.
-# It represents an XRP payment between two parties.
-#
-# If this parameter is unspecified, rippled will use an internal
-# default. Don't change this without understanding the consequences.
-#
-# Example:
-# reference_fee = 10 # 10 drops
-#
-# account_reserve =
-#
-# The account reserve requirement is specified in drops. The portion of an
-# account's XRP balance that is at or below the reserve may only be
-# spent on transaction fees, and not transferred out of the account.
-#
-# If this parameter is unspecified, rippled will use an internal
-# default. Don't change this without understanding the consequences.
-#
-# Example:
-# account_reserve = 20000000 # 20 XRP
-#
-# owner_reserve =
-#
-# The owner reserve is the amount of XRP reserved in the account for
-# each ledger item owned by the account. Ledger items an account may
-# own include trust lines, open orders, and tickets.
-#
-# If this parameter is unspecified, rippled will use an internal
-# default. Don't change this without understanding the consequences.
-#
-# Example:
-# owner_reserve = 5000000 # 5 XRP
-#
-#-------------------------------------------------------------------------------
-#
-# 8. Misc Settings
-#
-#-----------------
-#
-# [signing_support]
-#
-# Specifies whether the server will accept "sign" and "sign_for" commands
-# from remote users. Even if the commands are sent over a secure protocol
-# like secure websocket, this should generally be discouraged, because it
-# requires sending the secret to use for signing to the server. In order
-# to sign transactions, users should prefer to use a standalone signing
-# tool instead.
-#
-# This flag has no effect on the "sign" and "sign_for" command line options
-# that rippled makes available.
-#
-# The default value of this field is "false"
-#
-# Example:
-#
-# [signing_support]
-# true
-#
-# [crawl]
-#
-# List of options to control what data is reported through the /crawl endpoint
-# See https://xrpl.org/peer-crawler.html
-#
-#
-#
-# Enable or disable access to /crawl requests. Default is '1' which
-# enables access.
-#
-# overlay =
-#
-# Report information about peers this server is connected to, similar
-# to the "peers" RPC API. Default is '1' which means to report peer
-# overlay info.
-#
-# server =
-#
-# Report information about the local server, similar to the "server_state"
-# RPC API. Default is '1' which means to report local server info.
-#
-# counts =
-#
-# Report information about the local server health counters, similar to
-# the "get_counts" RPC API. Default is '0' which means not to report
-# server counts.
-#
-# unl =
-#
-# Report information about the local server's validator lists, similar to
-# the "validators" and "validator_list_sites" RPC APIs. Default is '1'
-# which means to report server validator lists.
-#
-# Examples:
-#
-# [crawl]
-# 0
-#
-# [crawl]
-# overlay = 1
-# server = 1
-# counts = 0
-# unl = 1
-#
-# [vl]
-#
-# Options to control what data is reported through the /vl endpoint
-# See [...]
-#
-# enable =
-#
-# Enable or disable access to /vl requests. Default is '1' which
-# enables access.
-#
-#-------------------------------------------------------------------------------
-#
-# 9. Example Settings
-#
-#--------------------
-#
-# Administrators can use these values as a starting point for configuring
-# their instance of rippled, but each value should be checked to make sure
-# it meets the business requirements for the organization.
-#
-# Server
-#
-# These example configuration settings create these ports:
-#
-# "peer"
-#
-# Peer protocol open to everyone. This is required to accept
-# incoming rippled connections. This does not affect automatic
-# or manual outgoing Peer protocol connections.
-#
-# "rpc"
-#
-# Administrative RPC commands over HTTPS, when originating from
-# the same machine (via the loopback adapter at 0.0.0.0).
-#
-# "wss_admin"
-#
-# Admin level API commands over Secure Websockets, when originating
-# from the same machine (via the loopback adapter at 0.0.0.0).
-#
-# This port is commented out but can be enabled by removing
-# the '#' from each corresponding line including the entry under [server]
-#
-# "wss_public"
-#
-# Guest level API commands over Secure Websockets, open to everyone.
-#
-# For HTTPS and Secure Websockets ports, if no certificate and key file
-# are specified then a self-signed certificate will be generated on startup.
-# If you have a certificate and key file, uncomment the corresponding lines
-# and ensure the paths to the files are correct.
-#
-# NOTE
-#
-# To accept connections on well known ports such as 80 (HTTP) or
-# 443 (HTTPS), most operating systems will require rippled to
-# run with administrator privileges, or else rippled will not start.
-
-[server]
-port_rpc_admin_local
-port_peer
-port_ws_admin_local
-port_ws_public
-#ssl_key = /etc/ssl/private/server.key
-#ssl_cert = /etc/ssl/certs/server.crt
[port_rpc_admin_local]
port = 5005
@@ -1192,40 +55,34 @@ port = 6006
ip = 0.0.0.0
protocol = ws
-#-------------------------------------------------------------------------------
-
[node_size]
-tiny
+small
+
+# tiny
+# small
+# medium
+# large
+# huge
-# This is primary persistent datastore for rippled. This includes transaction
-# metadata, account states, and ledger headers. Helpful information can be
-# found here: https://ripple.com/wiki/NodeBackEnd
-# delete old ledgers while maintaining at least 2000. Do not require an
-# external administrative command to initiate deletion.
[node_db]
-type=RocksDB
-path=/var/lib/rippled/db/rocksdb
-open_files=2000
-filter_bits=12
-cache_mb=256
-file_size_mb=8
-file_size_mult=2
-online_delete=2000
+type=NuDB
+path=/var/lib/rippled/db/nudb
advisory_delete=0
-# This is the persistent datastore for shards. It is important for the health
-# of the ripple network that rippled operators shard as much as practical.
-# NuDB requires SSD storage. Helpful information can be found here
-# https://ripple.com/build/history-sharding
-#[shard_db]
-#path=/var/lib/rippled/db/shards/nudb
-#max_size_gb=500
+# How many ledgers do we want to keep (history)?
+# Integer value that defines the number of ledgers
+# between online deletion events
+online_delete=2000
+
+#[ledger_history]
+# How many ledgers do we want to keep (history)?
+# Integer value (ledger count)
+# or (if you have lots of TB SSD storage): 'full'
+#256
[database_path]
/var/lib/rippled/db
-# This needs to be an absolute directory reference, not a relative one.
-# Modify this value as required.
[debug_logfile]
/var/log/rippled/debug.log
@@ -1235,12 +92,8 @@ time.apple.com
time.nist.gov
pool.ntp.org
-# To use the XRP test network (see https://ripple.com/build/xrp-test-net/),
-# use the following [ips] section:
-# [ips]
-# r.altnet.rippletest.net 51235
-
-# validator public key: nHBP8eqEWPnExo6ubTAV5QhUA3ZXVQYyT2qtKqxczFyoaKVhFh8M
+#[ips]
+#r.ripple.com 51235
[validator_token]
eyJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUwRlZqOEdmME84OG8xYlFmRk42dWJkV05LQlh3S1VH
@@ -1258,33 +111,96 @@ RkI0OTE5RDU0Njg0QjYifQ==
[validators_file]
validators.txt
-
-
-# Turn down default logging to save disk space in the long run.
-# Valid values here are trace, debug, info, warning, error, and fatal
[rpc_startup]
-{ "command": "log_level", "severity": "trace" }
+{ "command": "log_level", "severity": "info" }
+
+# severity (order: lots of information .. only errors)
+# debug
+# info
+# warn
+# error
+# fatal
-# If ssl_verify is 1, certificates will be validated.
-# To allow the use of self-signed certificates for development or internal use,
-# set to ssl_verify to 0.
[ssl_verify]
0
-[voting]
-account_reserve = 20000000 # 20 XRP
-owner_reserve = 5000000 # 5 XRP
-reference_fee = 10 # 10 drops
+
+# In order to enable an amendment which by default would vote "No", you must include its amendment id and name here.
+# To add amendments specifically from the latest releases of rippled:
+# 1. Go to https://xrpl.org/known-amendments.html
+# 2. Find the first amendment in the latest releases of rippled which are not already in the list below
+# 3. Click on each amendment to get their Amendment ID and name to add to this list manually.
+# You will likely update the list with all amendments from a new release of rippled all at once.
+
+# To get the list of amendments on a network (e.g. devnet) follow the steps in xrpl.js's CONTRIBUTING.md for "Updating the Docker container".
+# https://github.com/XRPLF/xrpl.js/blob/main/CONTRIBUTING.md
+# (Running the script `getNewAmendments.js` should help you identify any new amendments that should be added.)
+#
+# Note: The version of rippled you use this config with must have an implementation for the amendments you attempt to enable or it will crash.
+# If you need the version of rippled to be more up to date, you may need to make a comment on this repo: https://github.com/WietseWind/docker-rippled
[features]
+# Devnet amendments as of June 28th, 2023
+NegativeUNL
+fixRemoveNFTokenAutoTrustLine
+NonFungibleTokensV1
+CheckCashMakesTrustLine
+fixRmSmallIncreasedQOffers
+fixSTAmountCanonicalize
+FlowSortStrands
+TicketBatch
+fix1201
+fixQualityUpperBound
+FlowCross
+EnforceInvariants
+fix1523
+HardenedValidations
+DepositPreauth
+MultiSignReserve
+fix1623
+FeeEscalation
+PayChan
+fix1513
+RequireFullyCanonicalSig
+fix1543
+TickSize
+fix1781
+fixCheckThreading
+fix1515
+CryptoConditions
+fix1528
+fixPayChanRecipientOwnerDir
+SortedDirectories
+fix1578
+fix1571
+fixAmendmentMajorityCalc
+fixTakerDryOfferRemoval
+fixMasterKeyAsRegularKey
+Flow
+Escrow
+TrustSetAuth
+DeletableAccounts
+DepositAuth
+fix1368
+fix1512
+fix1373
+MultiSign
+Checks
NonFungibleTokensV1_1
+# 1.10.0 Amendments
DisallowIncoming
fixNonFungibleTokensV1_2
fixTrustLinesToSelf
fixUniversalNumber
ImmediateOfferKilled
XRPFees
-fixNFTokenRemint
-fixReducedOffersV1
+# 1.11.0 Amendments
+ExpandedSignerList
+# 1.12.0 Amendments
+AMM
Clawback
-AMM
\ No newline at end of file
+fixReducedOffersV1
+fixNFTokenRemint
+# 2.0.0 Amendments
+XChainBridge
+DID
\ No newline at end of file
From 774d60ff3c9aef1851407bb1117d9e2cbad2471e Mon Sep 17 00:00:00 2001
From: nkramer44
Date: Mon, 4 Dec 2023 11:07:34 -0500
Subject: [PATCH 2/4] DID Support (#498)
* Add XChainAccountCreateCommit transaction, as well as new XChainBridge serialized type
* Add XChainAddAccountCreateAttestation
* Add XChainAddClaimAttestation
* Fix bug in binary codec's UInt64Type where it expected JSON values to be base 10, not base 16. Also serialize XChainClaimIds as hex in JSON, and add a new XChainCount type that also serializes to hex in JSON
* add XChainClaim
* add XChainClaim
* add XChainCommit
* Add XChainCreateBridge
* Add XChainCreateClaimId
* add XChainModifyBridge
* Add Bridge object
* Add XChainOwnedCreateAccountClaimIdObject
* rename XChainCreateAccountProofSigWrapper to XChainCreateAccountAttestation
* add XChainOwnedClaimIdObject
* fix checkstyle and javadoc
* migrate to rippleci/rippled from xrpllabsofficial/xrpld.
Add new transactions to SignatureUtils switches
* write ITs for xchain stuff.
Add attestations that can be signed.
Add ability to sign attestations to signature services.
* fix checkstyle
* fix tests
* add DidSet transaction
* add DidDelete transaction
* add DidObject and MetaDidObject
* add ledger_entry support for DID
* add bridge ledger entry lookup
* add DID ITs
* PR feedback
* uncomment test
* fix checkstyle
---
.../xrpl4j/crypto/signing/SignatureUtils.java | 18 ++
.../ledger/LedgerEntryRequestParams.java | 30 ++
.../jackson/modules/DidDataDeserializer.java | 46 +++
.../jackson/modules/DidDataSerializer.java | 46 +++
.../modules/DidDocumentDeserializer.java | 47 +++
.../modules/DidDocumentSerializer.java | 46 +++
.../jackson/modules/DidUriDeserializer.java | 46 +++
.../jackson/modules/DidUriSerializer.java | 46 +++
.../xrpl/xrpl4j/model/ledger/DidObject.java | 135 +++++++++
.../xrpl4j/model/ledger/LedgerObject.java | 12 +-
.../xrpl4j/model/transactions/DidDelete.java | 50 ++++
.../xrpl4j/model/transactions/DidSet.java | 75 +++++
.../model/transactions/Transaction.java | 2 +
.../model/transactions/TransactionType.java | 20 +-
.../xrpl4j/model/transactions/Wrappers.java | 66 +++++
.../transactions/metadata/MetaDidObject.java | 108 +++++++
.../metadata/MetaLedgerEntryType.java | 5 +
.../src/main/resources/definitions.json | 47 ++-
.../binary/BinarySerializationTests.java | 84 ++++++
.../crypto/signing/SignatureUtilsTest.java | 51 ++++
.../ledger/LedgerEntryRequestParamsTest.java | 46 +++
.../xrpl4j/model/ledger/DidObjectTest.java | 67 +++++
.../model/transactions/DidDataTest.java | 72 +++++
.../model/transactions/DidDeleteTest.java | 72 +++++
.../model/transactions/DidDocumentTest.java | 73 +++++
.../xrpl4j/model/transactions/DidSetTest.java | 116 ++++++++
.../xrpl4j/model/transactions/DidUriTest.java | 72 +++++
.../metadata/MetaLedgerEntryTypeTest.java | 2 +
.../src/test/resources/codec-fixtures.json | 27 ++
.../java/org/xrpl/xrpl4j/tests/DidIT.java | 270 ++++++++++++++++++
30 files changed, 1784 insertions(+), 13 deletions(-)
create mode 100644 xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDataDeserializer.java
create mode 100644 xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDataSerializer.java
create mode 100644 xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDocumentDeserializer.java
create mode 100644 xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDocumentSerializer.java
create mode 100644 xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidUriDeserializer.java
create mode 100644 xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidUriSerializer.java
create mode 100644 xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/ledger/DidObject.java
create mode 100644 xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/DidDelete.java
create mode 100644 xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/DidSet.java
create mode 100644 xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaDidObject.java
create mode 100644 xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/DidObjectTest.java
create mode 100644 xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDataTest.java
create mode 100644 xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDeleteTest.java
create mode 100644 xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDocumentTest.java
create mode 100644 xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidSetTest.java
create mode 100644 xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidUriTest.java
create mode 100644 xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/DidIT.java
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtils.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtils.java
index 9d4fb28c2..c8edb3b0c 100644
--- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtils.java
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtils.java
@@ -44,6 +44,8 @@
import org.xrpl.xrpl4j.model.transactions.CheckCreate;
import org.xrpl.xrpl4j.model.transactions.Clawback;
import org.xrpl.xrpl4j.model.transactions.DepositPreAuth;
+import org.xrpl.xrpl4j.model.transactions.DidDelete;
+import org.xrpl.xrpl4j.model.transactions.DidSet;
import org.xrpl.xrpl4j.model.transactions.EscrowCancel;
import org.xrpl.xrpl4j.model.transactions.EscrowCreate;
import org.xrpl.xrpl4j.model.transactions.EscrowFinish;
@@ -371,6 +373,14 @@ public SingleSignedTransaction addSignatureToTransact
transactionWithSignature = XChainModifyBridge.builder().from((XChainModifyBridge) transaction)
.transactionSignature(signature)
.build();
+ } else if (DidSet.class.isAssignableFrom(transaction.getClass())) {
+ transactionWithSignature = DidSet.builder().from((DidSet) transaction)
+ .transactionSignature(signature)
+ .build();
+ } else if (DidDelete.class.isAssignableFrom(transaction.getClass())) {
+ transactionWithSignature = DidDelete.builder().from((DidDelete) transaction)
+ .transactionSignature(signature)
+ .build();
} else {
// Should never happen, but will in a unit test if we miss one.
throw new IllegalArgumentException("Signing fields could not be added to the transaction.");
@@ -566,6 +576,14 @@ public T addMultiSignaturesToTransaction(T transaction,
transactionWithSignatures = XChainModifyBridge.builder().from((XChainModifyBridge) transaction)
.signers(signers)
.build();
+ } else if (DidSet.class.isAssignableFrom(transaction.getClass())) {
+ transactionWithSignatures = DidSet.builder().from((DidSet) transaction)
+ .signers(signers)
+ .build();
+ } else if (DidDelete.class.isAssignableFrom(transaction.getClass())) {
+ transactionWithSignatures = DidDelete.builder().from((DidDelete) transaction)
+ .signers(signers)
+ .build();
} else {
// Should never happen, but will in a unit test if we miss one.
throw new IllegalArgumentException("Signing fields could not be added to the transaction.");
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParams.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParams.java
index 11e675428..b850bcbfb 100644
--- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParams.java
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParams.java
@@ -14,6 +14,7 @@
import org.xrpl.xrpl4j.model.ledger.BridgeObject;
import org.xrpl.xrpl4j.model.ledger.CheckObject;
import org.xrpl.xrpl4j.model.ledger.DepositPreAuthObject;
+import org.xrpl.xrpl4j.model.ledger.DidObject;
import org.xrpl.xrpl4j.model.ledger.EscrowObject;
import org.xrpl.xrpl4j.model.ledger.LedgerObject;
import org.xrpl.xrpl4j.model.ledger.NfTokenPageObject;
@@ -323,6 +324,24 @@ static LedgerEntryRequestParams bridge(
.build();
}
+ /**
+ * Construct a {@link LedgerEntryRequestParams} that requests a {@link DidObject} ledger entry.
+ *
+ * @param address The address of the owner of the {@link DidObject}.
+ * @param ledgerSpecifier A {@link LedgerSpecifier} indicating the ledger to query data from.
+ *
+ * @return A {@link LedgerEntryRequestParams} for {@link DidObject}.
+ */
+ static LedgerEntryRequestParams did(
+ Address address,
+ LedgerSpecifier ledgerSpecifier
+ ) {
+ return ImmutableLedgerEntryRequestParams.builder()
+ .did(address)
+ .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.
@@ -425,6 +444,13 @@ default boolean binary() {
*/
Optional ticket();
+ /**
+ * Loop up a {@link org.xrpl.xrpl4j.model.ledger.DidObject} by {@link Address}.
+ *
+ * @return An optionally-present {@link Address}.
+ */
+ Optional did();
+
/**
* Look up a {@link org.xrpl.xrpl4j.model.ledger.BridgeObject} by {@link Address}. The {@link #bridge()} field must
* also be present.
@@ -495,6 +521,10 @@ default Class ledgerObjectClass() {
return (Class) BridgeObject.class;
}
+ if (did().isPresent()) {
+ return (Class) DidObject.class;
+ }
+
return (Class) LedgerObject.class;
}
}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDataDeserializer.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDataDeserializer.java
new file mode 100644
index 000000000..0cef2de06
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDataDeserializer.java
@@ -0,0 +1,46 @@
+package org.xrpl.xrpl4j.model.jackson.modules;
+
+/*-
+ * ========================LICENSE_START=================================
+ * xrpl4j :: model
+ * %%
+ * Copyright (C) 2020 - 2022 XRPL Foundation and its contributors
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =========================LICENSE_END==================================
+ */
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.xrpl.xrpl4j.model.transactions.DidData;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson deserializer for {@link DidData}s.
+ */
+public class DidDataDeserializer extends StdDeserializer {
+
+ /**
+ * No-args constructor.
+ */
+ public DidDataDeserializer() {
+ super(DidData.class);
+ }
+
+ @Override
+ public DidData deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
+ return DidData.of(jsonParser.getText());
+ }
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDataSerializer.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDataSerializer.java
new file mode 100644
index 000000000..13118f096
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDataSerializer.java
@@ -0,0 +1,46 @@
+package org.xrpl.xrpl4j.model.jackson.modules;
+
+/*-
+ * ========================LICENSE_START=================================
+ * xrpl4j :: model
+ * %%
+ * Copyright (C) 2020 - 2022 XRPL Foundation and its contributors
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =========================LICENSE_END==================================
+ */
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
+import org.xrpl.xrpl4j.model.transactions.DidData;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson serializer for {@link DidData}s.
+ */
+public class DidDataSerializer extends StdScalarSerializer {
+
+ /**
+ * No-args constructor.
+ */
+ public DidDataSerializer() {
+ super(DidData.class, false);
+ }
+
+ @Override
+ public void serialize(DidData didData, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(didData.value());
+ }
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDocumentDeserializer.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDocumentDeserializer.java
new file mode 100644
index 000000000..82d66db52
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDocumentDeserializer.java
@@ -0,0 +1,47 @@
+package org.xrpl.xrpl4j.model.jackson.modules;
+
+/*-
+ * ========================LICENSE_START=================================
+ * xrpl4j :: model
+ * %%
+ * Copyright (C) 2020 - 2022 XRPL Foundation and its contributors
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =========================LICENSE_END==================================
+ */
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.DidDocument;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson deserializer for {@link DidDocument}s.
+ */
+public class DidDocumentDeserializer extends StdDeserializer {
+
+ /**
+ * No-args constructor.
+ */
+ public DidDocumentDeserializer() {
+ super(DidDocument.class);
+ }
+
+ @Override
+ public DidDocument deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
+ return DidDocument.of(jsonParser.getText());
+ }
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDocumentSerializer.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDocumentSerializer.java
new file mode 100644
index 000000000..d501a689b
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidDocumentSerializer.java
@@ -0,0 +1,46 @@
+package org.xrpl.xrpl4j.model.jackson.modules;
+
+/*-
+ * ========================LICENSE_START=================================
+ * xrpl4j :: model
+ * %%
+ * Copyright (C) 2020 - 2022 XRPL Foundation and its contributors
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =========================LICENSE_END==================================
+ */
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
+import org.xrpl.xrpl4j.model.transactions.DidDocument;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson serializer for {@link DidDocument}s.
+ */
+public class DidDocumentSerializer extends StdScalarSerializer {
+
+ /**
+ * No-args constructor.
+ */
+ public DidDocumentSerializer() {
+ super(DidDocument.class, false);
+ }
+
+ @Override
+ public void serialize(DidDocument didDocument, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(didDocument.value());
+ }
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidUriDeserializer.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidUriDeserializer.java
new file mode 100644
index 000000000..f7fd538cf
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidUriDeserializer.java
@@ -0,0 +1,46 @@
+package org.xrpl.xrpl4j.model.jackson.modules;
+
+/*-
+ * ========================LICENSE_START=================================
+ * xrpl4j :: model
+ * %%
+ * Copyright (C) 2020 - 2022 XRPL Foundation and its contributors
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =========================LICENSE_END==================================
+ */
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.xrpl.xrpl4j.model.transactions.DidUri;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson deserializer for {@link DidUri}s.
+ */
+public class DidUriDeserializer extends StdDeserializer {
+
+ /**
+ * No-args constructor.
+ */
+ public DidUriDeserializer() {
+ super(DidUri.class);
+ }
+
+ @Override
+ public DidUri deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
+ return DidUri.of(jsonParser.getText());
+ }
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidUriSerializer.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidUriSerializer.java
new file mode 100644
index 000000000..6322e5e50
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/DidUriSerializer.java
@@ -0,0 +1,46 @@
+package org.xrpl.xrpl4j.model.jackson.modules;
+
+/*-
+ * ========================LICENSE_START=================================
+ * xrpl4j :: model
+ * %%
+ * Copyright (C) 2020 - 2022 XRPL Foundation and its contributors
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =========================LICENSE_END==================================
+ */
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
+import org.xrpl.xrpl4j.model.transactions.DidUri;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson serializer for {@link DidUri}s.
+ */
+public class DidUriSerializer extends StdScalarSerializer {
+
+ /**
+ * No-args constructor.
+ */
+ public DidUriSerializer() {
+ super(DidUri.class, false);
+ }
+
+ @Override
+ public void serialize(DidUri didUri, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(didUri.value());
+ }
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/ledger/DidObject.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/ledger/DidObject.java
new file mode 100644
index 000000000..af408be19
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/ledger/DidObject.java
@@ -0,0 +1,135 @@
+package org.xrpl.xrpl4j.model.ledger;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.annotations.Beta;
+import com.google.common.primitives.UnsignedInteger;
+import org.immutables.value.Value;
+import org.immutables.value.Value.Immutable;
+import org.xrpl.xrpl4j.model.flags.Flags;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.DidData;
+import org.xrpl.xrpl4j.model.transactions.DidDocument;
+import org.xrpl.xrpl4j.model.transactions.DidUri;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.XChainBridge;
+import org.xrpl.xrpl4j.model.transactions.XChainCount;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * A {@code DID} ledger entry holds references to, or data associated with a single DID.
+ *
+ * This interface will be marked {@link Beta} until the featureDID amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableDidObject.class)
+@JsonDeserialize(as = ImmutableDidObject.class)
+public interface DidObject extends LedgerObject {
+
+ /**
+ * Construct a {@code DidObject} builder.
+ *
+ * @return An {@link ImmutableDidObject.Builder}.
+ */
+ static ImmutableDidObject.Builder builder() {
+ return ImmutableDidObject.builder();
+ }
+
+ /**
+ * The type of ledger object, which will always be "DID" in this case.
+ *
+ * @return Always returns {@link LedgerEntryType#DID}.
+ */
+ @JsonProperty("LedgerEntryType")
+ @Value.Derived
+ default LedgerEntryType ledgerEntryType() {
+ return LedgerEntryType.DID;
+ }
+
+ /**
+ * A bit-map of boolean flags. No flags are defined for {@link DidObject}, so this value is always 0.
+ *
+ * @return Always {@link Flags#UNSET}.
+ */
+ @JsonProperty("Flags")
+ @Value.Derived
+ default Flags flags() {
+ return Flags.UNSET;
+ }
+
+ /**
+ * The account that controls the DID.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("Account")
+ Address account();
+
+ /**
+ * The W3C standard DID document associated with the DID. This field isn't checked for validity and is limited to a
+ * maximum length of 256 bytes.
+ *
+ * @return An optionally-present {@link DidDocument}.
+ */
+ @JsonProperty("DIDDocument")
+ Optional didDocument();
+
+ /**
+ * The public attestations of identity credentials associated with the DID. This field isn't checked for validity and
+ * is limited to a maximum length of 256 bytes.
+ *
+ * @return An optionally-present {@link DidData}.
+ */
+ @JsonProperty("Data")
+ Optional data();
+
+ /**
+ * The Universal Resource Identifier that points to the corresponding DID document or the data associated with the
+ * DID. This field can be an HTTP(S) URL or IPFS URI. This field isn't checked for validity and is limited to a
+ * maximum length of 256 bytes.
+ *
+ * @return An optionally-present {@link DidUri}.
+ */
+ @JsonProperty("URI")
+ Optional uri();
+
+ /**
+ * A hint indicating which page of the sender's owner directory links to this object, in case the directory consists
+ * of multiple pages.
+ *
+ * Note: The object does not contain a direct link to the owner directory containing it, since that value can be
+ * derived from the Account.
+ *
+ * @return A {@link String} containing the owner node hint.
+ */
+ @JsonProperty("OwnerNode")
+ String ownerNode();
+
+ /**
+ * The identifying hash of the transaction that most recently modified this object.
+ *
+ * @return A {@link Hash256} containing the previous transaction hash.
+ */
+ @JsonProperty("PreviousTxnID")
+ Hash256 previousTransactionId();
+
+ /**
+ * The index of the ledger that contains the transaction that most recently modified this object.
+ *
+ * @return An {@link UnsignedInteger} representing the previous transaction ledger sequence.
+ */
+ @JsonProperty("PreviousTxnLgrSeq")
+ UnsignedInteger previousTransactionLedgerSequence();
+
+ /**
+ * The unique ID of the {@link DidObject}.
+ *
+ * @return A {@link Hash256} containing the ID.
+ */
+ Hash256 index();
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/ledger/LedgerObject.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/ledger/LedgerObject.java
index ecbd3d316..e463234d5 100644
--- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/ledger/LedgerObject.java
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/ledger/LedgerObject.java
@@ -61,6 +61,7 @@
name = "XChainOwnedCreateAccountClaimID"
),
@JsonSubTypes.Type(value = ImmutableXChainOwnedClaimIdObject.class, name = "XChainOwnedClaimID"),
+ @JsonSubTypes.Type(value = ImmutableDidObject.class, name = "DID"),
})
// TODO: Uncomment subtypes as we implement
public interface LedgerObject {
@@ -184,7 +185,16 @@ enum LedgerEntryType {
* Its API is subject to change.
*/
@Beta
- XCHAIN_OWNED_CLAIM_ID("XChainOwnedClaimID");
+ XCHAIN_OWNED_CLAIM_ID("XChainOwnedClaimID"),
+
+ /**
+ * The {@link LedgerEntryType} for {@code DID} ledger objects.
+ *
+ * This constant will be marked {@link Beta} until the featureDID amendment is enabled on mainnet.
+ * Its API is subject to change.
+ */
+ @Beta
+ DID("DID");
private final String value;
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/DidDelete.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/DidDelete.java
new file mode 100644
index 000000000..91b27ff6b
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/DidDelete.java
@@ -0,0 +1,50 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+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;
+import org.immutables.value.Value.Immutable;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+
+import java.util.Optional;
+
+/**
+ * Object mapping for the {@code DIDDelete} transaction.
+ *
+ * This constant will be marked {@link Beta} until the featureDID amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableDidDelete.class)
+@JsonDeserialize(as = ImmutableDidDelete.class)
+public interface DidDelete extends Transaction {
+
+ /**
+ * Construct a {@code DidDelete} builder.
+ *
+ * @return An {@link ImmutableDidDelete.Builder}.
+ */
+ static ImmutableDidDelete.Builder builder() {
+ return ImmutableDidDelete.builder();
+ }
+
+ /**
+ * Set of {@link TransactionFlags}s for this {@link DidDelete}, which only allows the {@code tfFullyCanonicalSig}
+ * flag, which is deprecated.
+ *
+ * The value of the flags can be set manually, but exists mostly for JSON serialization/deserialization only and
+ * for proper signature computation in rippled.
+ *
+ * @return Always {@link TransactionFlags#EMPTY}.
+ */
+ @JsonProperty("Flags")
+ @Value.Default
+ default TransactionFlags flags() {
+ return TransactionFlags.EMPTY;
+ }
+
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/DidSet.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/DidSet.java
new file mode 100644
index 000000000..95559bfe8
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/DidSet.java
@@ -0,0 +1,75 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+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;
+import org.immutables.value.Value.Immutable;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+
+import java.util.Optional;
+
+/**
+ * Object mapping for the {@code DIDSet} transaction.
+ *
+ *
This constant will be marked {@link Beta} until the featureDID amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableDidSet.class)
+@JsonDeserialize(as = ImmutableDidSet.class)
+public interface DidSet extends Transaction {
+
+ /**
+ * Construct a {@code DidSet} builder.
+ *
+ * @return An {@link ImmutableDidSet.Builder}.
+ */
+ static ImmutableDidSet.Builder builder() {
+ return ImmutableDidSet.builder();
+ }
+
+ /**
+ * Set of {@link TransactionFlags}s for this {@link DidSet}, which only allows the {@code tfFullyCanonicalSig} flag,
+ * which is deprecated.
+ *
+ * The value of the flags can be set manually, but exists mostly for JSON serialization/deserialization only and
+ * for proper signature computation in rippled.
+ *
+ * @return Always {@link TransactionFlags#EMPTY}.
+ */
+ @JsonProperty("Flags")
+ @Value.Default
+ default TransactionFlags flags() {
+ return TransactionFlags.EMPTY;
+ }
+
+ /**
+ * The DID document for this DID. This field should contain a DID Document per W3C standards, however its contents
+ * are not checked for validity by the XRPL.
+ *
+ * @return An optionally-present {@link DidDocument}.
+ */
+ @JsonProperty("DIDDocument")
+ Optional didDocument();
+
+ /**
+ * The Universal Resource Identifier associated with the DID.
+ *
+ * @return An optionally-present {@link DidUri}.
+ */
+ @JsonProperty("URI")
+ Optional uri();
+
+ /**
+ * The public attestations of identity credentials associated with the DID.
+ *
+ * @return An optionalyl-present {@link DidData}.
+ */
+ @JsonProperty("Data")
+ Optional data();
+
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java
index 4c74c491b..40c3e7695 100644
--- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java
@@ -86,6 +86,8 @@ public interface Transaction {
.put(ImmutableXChainCreateBridge.class, TransactionType.XCHAIN_CREATE_BRIDGE)
.put(ImmutableXChainCreateClaimId.class, TransactionType.XCHAIN_CREATE_CLAIM_ID)
.put(ImmutableXChainModifyBridge.class, TransactionType.XCHAIN_MODIFY_BRIDGE)
+ .put(ImmutableDidSet.class, TransactionType.DID_SET)
+ .put(ImmutableDidDelete.class, TransactionType.DID_DELETE)
.build();
/**
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/TransactionType.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/TransactionType.java
index 91f7d2d59..244e00544 100644
--- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/TransactionType.java
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/TransactionType.java
@@ -300,7 +300,25 @@ public enum TransactionType {
* is subject to change.
*/
@Beta
- XCHAIN_MODIFY_BRIDGE("XChainModifyBridge");
+ XCHAIN_MODIFY_BRIDGE("XChainModifyBridge"),
+
+ /**
+ * The {@link TransactionType} for the {@link DidSet} transaction.
+ *
+ * This constant will be marked {@link Beta} until the featureDID amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+ @Beta
+ DID_SET("DIDSet"),
+
+ /**
+ * The {@link TransactionType} for the {@link DidDelete} transaction.
+ *
+ * This constant will be marked {@link Beta} until the featureDID amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+ @Beta
+ DID_DELETE("DIDDelete");
private final String value;
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/Wrappers.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/Wrappers.java
index 3558d0c9e..883843409 100644
--- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/Wrappers.java
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/Wrappers.java
@@ -34,6 +34,12 @@
import org.xrpl.xrpl4j.model.immutables.Wrapper;
import org.xrpl.xrpl4j.model.jackson.modules.AddressDeserializer;
import org.xrpl.xrpl4j.model.jackson.modules.AddressSerializer;
+import org.xrpl.xrpl4j.model.jackson.modules.DidDataDeserializer;
+import org.xrpl.xrpl4j.model.jackson.modules.DidDataSerializer;
+import org.xrpl.xrpl4j.model.jackson.modules.DidDocumentDeserializer;
+import org.xrpl.xrpl4j.model.jackson.modules.DidDocumentSerializer;
+import org.xrpl.xrpl4j.model.jackson.modules.DidUriDeserializer;
+import org.xrpl.xrpl4j.model.jackson.modules.DidUriSerializer;
import org.xrpl.xrpl4j.model.jackson.modules.Hash256Deserializer;
import org.xrpl.xrpl4j.model.jackson.modules.Hash256Serializer;
import org.xrpl.xrpl4j.model.jackson.modules.MarkerDeserializer;
@@ -536,4 +542,64 @@ public String toString() {
}
}
+
+ /**
+ * A wrapped {@link String} containing a DID Document.
+ *
+ * This class will be marked {@link com.google.common.annotations.Beta} until the featureDID amendment is
+ * enabled on mainnet. Its API is subject to change.
+ */
+ @Value.Immutable
+ @Wrapped
+ @JsonSerialize(as = DidDocument.class, using = DidDocumentSerializer.class)
+ @JsonDeserialize(as = DidDocument.class, using = DidDocumentDeserializer.class)
+ @Beta
+ abstract static class _DidDocument extends Wrapper implements Serializable {
+
+ @Override
+ public String toString() {
+ return this.value();
+ }
+
+ }
+
+ /**
+ * A wrapped {@link String} containing a DID URI.
+ *
+ * This class will be marked {@link com.google.common.annotations.Beta} until the featureDID amendment is
+ * enabled on mainnet. Its API is subject to change.
+ */
+ @Value.Immutable
+ @Wrapped
+ @JsonSerialize(as = DidUri.class, using = DidUriSerializer.class)
+ @JsonDeserialize(as = DidUri.class, using = DidUriDeserializer.class)
+ @Beta
+ abstract static class _DidUri extends Wrapper implements Serializable {
+
+ @Override
+ public String toString() {
+ return this.value();
+ }
+
+ }
+
+ /**
+ * A wrapped {@link String} containing DID Data.
+ *
+ * This class will be marked {@link com.google.common.annotations.Beta} until the featureDID amendment is
+ * enabled on mainnet. Its API is subject to change.
+ */
+ @Value.Immutable
+ @Wrapped
+ @JsonSerialize(as = DidData.class, using = DidDataSerializer.class)
+ @JsonDeserialize(as = DidData.class, using = DidDataDeserializer.class)
+ @Beta
+ abstract static class _DidData extends Wrapper implements Serializable {
+
+ @Override
+ public String toString() {
+ return this.value();
+ }
+
+ }
}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaDidObject.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaDidObject.java
new file mode 100644
index 000000000..cbfddc267
--- /dev/null
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaDidObject.java
@@ -0,0 +1,108 @@
+package org.xrpl.xrpl4j.model.transactions.metadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.annotations.Beta;
+import com.google.common.primitives.UnsignedInteger;
+import org.immutables.value.Value;
+import org.immutables.value.Value.Immutable;
+import org.xrpl.xrpl4j.model.flags.Flags;
+import org.xrpl.xrpl4j.model.ledger.ImmutableDidObject;
+import org.xrpl.xrpl4j.model.ledger.LedgerObject;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.DidData;
+import org.xrpl.xrpl4j.model.transactions.DidDocument;
+import org.xrpl.xrpl4j.model.transactions.DidUri;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+
+import java.util.Optional;
+
+/**
+ * A {@code DID} ledger entry holds references to, or data associated with a single DID.
+ *
+ * This interface will be marked {@link Beta} until the featureDID amendment is enabled on mainnet. Its API
+ * is subject to change.
+ */
+@Beta
+@Immutable
+@JsonSerialize(as = ImmutableMetaDidObject.class)
+@JsonDeserialize(as = ImmutableMetaDidObject.class)
+public interface MetaDidObject extends MetaLedgerObject {
+
+ /**
+ * A bit-map of boolean flags. No flags are defined for {@link MetaDidObject}, so this value is always 0.
+ *
+ * @return Always {@link Flags#UNSET}.
+ */
+ @JsonProperty("Flags")
+ @Value.Derived
+ default Flags flags() {
+ return Flags.UNSET;
+ }
+
+ /**
+ * The account that controls the DID.
+ *
+ * @return An {@link Address}.
+ */
+ @JsonProperty("Account")
+ Optional account();
+
+ /**
+ * The W3C standard DID document associated with the DID. This field isn't checked for validity and is limited to a
+ * maximum length of 256 bytes.
+ *
+ * @return An optionally-present {@link DidDocument}.
+ */
+ @JsonProperty("DIDDocument")
+ Optional didDocument();
+
+ /**
+ * The public attestations of identity credentials associated with the DID. This field isn't checked for validity and
+ * is limited to a maximum length of 256 bytes.
+ *
+ * @return An optionally-present {@link DidData}.
+ */
+ @JsonProperty("Data")
+ Optional data();
+
+ /**
+ * The Universal Resource Identifier that points to the corresponding DID document or the data associated with the
+ * DID. This field can be an HTTP(S) URL or IPFS URI. This field isn't checked for validity and is limited to a
+ * maximum length of 256 bytes.
+ *
+ * @return An optionally-present {@link DidUri}.
+ */
+ @JsonProperty("URI")
+ Optional uri();
+
+ /**
+ * A hint indicating which page of the sender's owner directory links to this object, in case the directory consists
+ * of multiple pages.
+ *
+ * Note: The object does not contain a direct link to the owner directory containing it, since that value can be
+ * derived from the Account.
+ *
+ * @return A {@link String} containing the owner node hint.
+ */
+ @JsonProperty("OwnerNode")
+ Optional ownerNode();
+
+ /**
+ * The identifying hash of the transaction that most recently modified this object.
+ *
+ * @return A {@link Hash256} containing the previous transaction hash.
+ */
+ @JsonProperty("PreviousTxnID")
+ Optional previousTransactionId();
+
+ /**
+ * The index of the ledger that contains the transaction that most recently modified this object.
+ *
+ * @return An {@link UnsignedInteger} representing the previous transaction ledger sequence.
+ */
+ @JsonProperty("PreviousTxnLgrSeq")
+ Optional previousTransactionLedgerSequence();
+
+}
diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryType.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryType.java
index 8c1a24936..b913bc70f 100644
--- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryType.java
+++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryType.java
@@ -41,6 +41,9 @@ public interface MetaLedgerEntryType {
@Beta
MetaLedgerEntryType XCHAIN_OWNED_CLAIM_ID = MetaLedgerEntryType.of("XChainOwnedClaimID");
+ @Beta
+ MetaLedgerEntryType DID = MetaLedgerEntryType.of("DID");
+
/**
* Construct a new {@link MetaLedgerEntryType} from a {@link String}.
*
@@ -93,6 +96,8 @@ default Class extends MetaLedgerObject> ledgerObjectType() {
return MetaXChainOwnedClaimIdObject.class;
case "XChainOwnedCreateAccountClaimID":
return MetaXChainOwnedCreateAccountClaimIdObject.class;
+ case "DID":
+ return MetaDidObject.class;
default:
return MetaUnknownObject.class;
}
diff --git a/xrpl4j-core/src/main/resources/definitions.json b/xrpl4j-core/src/main/resources/definitions.json
index b6b48f440..b8fd9a8a1 100644
--- a/xrpl4j-core/src/main/resources/definitions.json
+++ b/xrpl4j-core/src/main/resources/definitions.json
@@ -50,6 +50,7 @@
"NFTokenPage": 80,
"NFTokenOffer": 55,
"AMM": 121,
+ "DID": 73,
"Any": -3,
"Child": -2,
"Nickname": 110,
@@ -140,40 +141,40 @@
[
"LedgerEntry",
{
- "nth": 1,
+ "nth": 257,
"isVLEncoded": false,
"isSerialized": false,
- "isSigningField": true,
+ "isSigningField": false,
"type": "LedgerEntry"
}
],
[
"Transaction",
{
- "nth": 1,
+ "nth": 257,
"isVLEncoded": false,
"isSerialized": false,
- "isSigningField": true,
+ "isSigningField": false,
"type": "Transaction"
}
],
[
"Validation",
{
- "nth": 1,
+ "nth": 257,
"isVLEncoded": false,
"isSerialized": false,
- "isSigningField": true,
+ "isSigningField": false,
"type": "Validation"
}
],
[
"Metadata",
{
- "nth": 1,
+ "nth": 257,
"isVLEncoded": false,
- "isSerialized": true,
- "isSigningField": true,
+ "isSerialized": false,
+ "isSigningField": false,
"type": "Metadata"
}
],
@@ -1897,6 +1898,26 @@
"type": "Blob"
}
],
+ [
+ "DIDDocument",
+ {
+ "nth": 26,
+ "isVLEncoded": true,
+ "isSerialized": true,
+ "isSigningField": true,
+ "type": "Blob"
+ }
+ ],
+ [
+ "Data",
+ {
+ "nth": 27,
+ "isVLEncoded": true,
+ "isSerialized": true,
+ "isSigningField": true,
+ "type": "Blob"
+ }
+ ],
[
"Account",
{
@@ -2681,6 +2702,7 @@
"temXCHAIN_BRIDGE_NONDOOR_OWNER": -257,
"temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT": -256,
"temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT": -255,
+ "temEMPTY_DID": -254,
"tefFAILURE": -199,
"tefALREADY": -198,
@@ -2759,7 +2781,7 @@
"tecKILLED": 150,
"tecHAS_OBLIGATIONS": 151,
"tecTOO_SOON": 152,
- "tecHOOK_ERROR": 153,
+ "tecHOOK_REJECTED": 153,
"tecMAX_SEQUENCE_REACHED": 154,
"tecNO_SUITABLE_NFTOKEN_PAGE": 155,
"tecNFTOKEN_BUY_SELL_MISMATCH": 156,
@@ -2792,7 +2814,8 @@
"tecXCHAIN_PAYMENT_FAILED": 183,
"tecXCHAIN_SELF_COMMIT": 184,
"tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR": 185,
- "tecXCHAIN_CREATE_ACCOUNT_DISABLED": 186
+ "tecXCHAIN_CREATE_ACCOUNT_DISABLED": 186,
+ "tecEMPTY_DID": 187
},
"TRANSACTION_TYPES": {
"Invalid": -1,
@@ -2839,6 +2862,8 @@
"XChainAddAccountCreateAttestation": 46,
"XChainModifyBridge": 47,
"XChainCreateBridge": 48,
+ "DIDSet": 49,
+ "DIDDelete": 50,
"EnableAmendment": 100,
"SetFee": 101,
"UNLModify": 102
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java
index 292c14e30..d22654441 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java
@@ -57,10 +57,17 @@
import org.xrpl.xrpl4j.model.transactions.CheckCreate;
import org.xrpl.xrpl4j.model.transactions.CurrencyAmount;
import org.xrpl.xrpl4j.model.transactions.DepositPreAuth;
+import org.xrpl.xrpl4j.model.transactions.DidData;
+import org.xrpl.xrpl4j.model.transactions.DidDelete;
+import org.xrpl.xrpl4j.model.transactions.DidDocument;
+import org.xrpl.xrpl4j.model.transactions.DidSet;
+import org.xrpl.xrpl4j.model.transactions.DidUri;
import org.xrpl.xrpl4j.model.transactions.EscrowCancel;
import org.xrpl.xrpl4j.model.transactions.EscrowCreate;
import org.xrpl.xrpl4j.model.transactions.EscrowFinish;
import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.ImmutableDidDelete;
+import org.xrpl.xrpl4j.model.transactions.ImmutableDidSet;
import org.xrpl.xrpl4j.model.transactions.ImmutableXChainAccountCreateCommit;
import org.xrpl.xrpl4j.model.transactions.ImmutableXChainAddClaimAttestation;
import org.xrpl.xrpl4j.model.transactions.ImmutableXChainClaim;
@@ -2036,6 +2043,83 @@ void serializeXChainModifyBridge() throws JsonProcessingException {
assertSerializesAndDeserializes(transaction, binary);
}
+ @Test
+ void serializeDidSet() throws JsonProcessingException {
+ DidSet transaction = DidSet.builder()
+ .account(Address.of("rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8"))
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .sequence(UnsignedInteger.valueOf(3))
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("ED9861C4CB029C0DA737B823D7D3459A70F227958D5C0C111CC7CF947FC5A93347")
+ )
+ .transactionSignature(
+ Signature.fromBase16("AACD31A04CAE14670FC483A1382F393AA96B49C84479B58067F049FBD7729993" +
+ "25667A6AA2520A63756EE84F3657298815019DD56A1AECE796B08535C4009C08")
+ )
+ .didDocument(DidDocument.of("646F63"))
+ .data(DidData.of("617474657374"))
+ .uri(DidUri.of("6469645F6578616D706C65"))
+ .build();
+
+ String binary = "1200312280000000240000000368400000000000000A7321ED9861C4CB029C0DA737B823D7D3459A70F227" +
+ "958D5C0C111CC7CF947FC5A933477440AACD31A04CAE14670FC483A1382F393AA96B49C84479B58067F049FBD77299932566" +
+ "7A6AA2520A63756EE84F3657298815019DD56A1AECE796B08535C4009C08750B6469645F6578616D706C65701A03646F6370" +
+ "1B06617474657374811401476926B590BA3245F63C829116A0A3AF7F382D";
+
+ assertSerializesAndDeserializes(transaction, binary);
+ }
+
+ @Test
+ void serializeDidSetWithEmptyValues() throws JsonProcessingException {
+ DidSet transaction = DidSet.builder()
+ .account(Address.of("rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8"))
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .sequence(UnsignedInteger.valueOf(3))
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("ED9861C4CB029C0DA737B823D7D3459A70F227958D5C0C111CC7CF947FC5A93347")
+ )
+ .transactionSignature(
+ Signature.fromBase16("AACD31A04CAE14670FC483A1382F393AA96B49C84479B58067F049FBD7729993" +
+ "25667A6AA2520A63756EE84F3657298815019DD56A1AECE796B08535C4009C08")
+ )
+ .didDocument(DidDocument.of(""))
+ .data(DidData.of(""))
+ .uri(DidUri.of(""))
+ .build();
+
+ String binary = "1200312280000000240000000368400000000000000A7321ED9861C4CB029C0DA737B823D7D3459A70F2" +
+ "27958D5C0C111CC7CF947FC5A933477440AACD31A04CAE14670FC483A1382F393AA96B49C84479B58067F049FBD7729993" +
+ "25667A6AA2520A63756EE84F3657298815019DD56A1AECE796B08535C4009C087500701A00701B00811401476926B590BA" +
+ "3245F63C829116A0A3AF7F382D";
+
+ assertSerializesAndDeserializes(transaction, binary);
+ }
+
+ @Test
+ void serializeDidDelete() throws JsonProcessingException {
+ DidDelete transaction = DidDelete.builder()
+ .account(Address.of("rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8"))
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.valueOf(4))
+ .signingPublicKey(
+ PublicKey.fromBase16EncodedPublicKey("ED9861C4CB029C0DA737B823D7D3459A70F227958D5C0C111CC7CF947FC5A93347")
+ )
+ .transactionSignature(
+ Signature.fromBase16("71E28B12465A1B47162C22E121DF61089DCD9AAF5773704B76179E771666" +
+ "886C8AAD5A33A87E34CC381A7D924E3FE3645F0BF98D565DE42C81E1A7A7E7981802")
+ )
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .build();
+
+ String binary = "1200322280000000240000000468400000000000000A7321ED9861C4CB029C0DA737B823D7D3459A70F22" +
+ "7958D5C0C111CC7CF947FC5A93347744071E28B12465A1B47162C22E121DF61089DCD9AAF5773704B76179E771666886C8AA" +
+ "D5A33A87E34CC381A7D924E3FE3645F0BF98D565DE42C81E1A7A7E7981802811401476926B590BA3245F63C829116A0A3AF7F382D";
+
+ assertSerializesAndDeserializes(transaction, binary);
+ }
+
private void assertSerializesAndDeserializes(
T transaction,
String expectedBinary
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtilsTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtilsTest.java
index 75e286c6e..e23dd9dcd 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtilsTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtilsTest.java
@@ -71,6 +71,11 @@
import org.xrpl.xrpl4j.model.transactions.CheckCreate;
import org.xrpl.xrpl4j.model.transactions.Clawback;
import org.xrpl.xrpl4j.model.transactions.DepositPreAuth;
+import org.xrpl.xrpl4j.model.transactions.DidData;
+import org.xrpl.xrpl4j.model.transactions.DidDelete;
+import org.xrpl.xrpl4j.model.transactions.DidDocument;
+import org.xrpl.xrpl4j.model.transactions.DidSet;
+import org.xrpl.xrpl4j.model.transactions.DidUri;
import org.xrpl.xrpl4j.model.transactions.EscrowCancel;
import org.xrpl.xrpl4j.model.transactions.EscrowCreate;
import org.xrpl.xrpl4j.model.transactions.EscrowFinish;
@@ -1080,6 +1085,30 @@ void addSignatureToXChainModifyBridge() {
addSignatureToTransactionHelper(transaction);
}
+ @Test
+ void addSignatureToDidSet() {
+ DidSet transaction = DidSet.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.valueOf(391))
+ .signingPublicKey(sourcePublicKey)
+ .build();
+
+ addSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addSignatureToDidDelete() {
+ DidDelete transaction = DidDelete.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.valueOf(391))
+ .signingPublicKey(sourcePublicKey)
+ .build();
+
+ addSignatureToTransactionHelper(transaction);
+ }
+
@Test
public void addSignatureToTransactionUnsupported() {
assertThrows(IllegalArgumentException.class, () -> addSignatureToTransactionHelper(transactionMock));
@@ -1673,6 +1702,28 @@ void addMultiSignatureToXChainModifyBridge() {
addMultiSignatureToTransactionHelper(transaction);
}
+ @Test
+ void addMultiSignatureToDidSet() {
+ DidSet transaction = DidSet.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.valueOf(391))
+ .build();
+
+ addMultiSignatureToTransactionHelper(transaction);
+ }
+
+ @Test
+ void addMultiSignatureToDidDelete() {
+ DidDelete transaction = DidDelete.builder()
+ .account(sourcePublicKey.deriveAddress())
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.valueOf(391))
+ .build();
+
+ addMultiSignatureToTransactionHelper(transaction);
+ }
+
@Test
public void addMultiSignaturesToTransactionUnsupported() {
when(transactionMock.transactionSignature()).thenReturn(Optional.empty());
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParamsTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParamsTest.java
index 9f3c3d1d8..62c272658 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParamsTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/client/ledger/LedgerEntryRequestParamsTest.java
@@ -19,6 +19,7 @@
import org.xrpl.xrpl4j.model.ledger.BridgeObject;
import org.xrpl.xrpl4j.model.ledger.CheckObject;
import org.xrpl.xrpl4j.model.ledger.DepositPreAuthObject;
+import org.xrpl.xrpl4j.model.ledger.DidObject;
import org.xrpl.xrpl4j.model.ledger.EscrowObject;
import org.xrpl.xrpl4j.model.ledger.Issue;
import org.xrpl.xrpl4j.model.ledger.LedgerObject;
@@ -52,6 +53,7 @@ void testTypedIndexParams() throws JSONException, JsonProcessingException {
assertThat(params.nftPage()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
+ assertThat(params.did()).isEmpty();
String json = String.format("{\n" +
" \"index\": \"%s\",\n" +
@@ -85,6 +87,7 @@ void testUntypedIndexParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -115,6 +118,7 @@ void testAccountRootParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -153,6 +157,7 @@ void testAmmParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -196,6 +201,7 @@ void testOfferParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -237,6 +243,7 @@ void testRippleStateParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -271,6 +278,7 @@ void testCheckParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -305,6 +313,7 @@ void testEscrowParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -338,6 +347,7 @@ void testPaymentChannelParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -373,6 +383,7 @@ void testDepositPreAuthParams() throws JSONException, JsonProcessingException {
assertThat(params.paymentChannel()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -411,6 +422,7 @@ void testTicketParams() throws JSONException, JsonProcessingException {
assertThat(params.paymentChannel()).isEmpty();
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -445,6 +457,7 @@ void testNftPageParams() throws JSONException, JsonProcessingException {
assertThat(params.paymentChannel()).isEmpty();
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
+ assertThat(params.did()).isEmpty();
assertThat(params.bridgeAccount()).isEmpty();
assertThat(params.bridge()).isEmpty();
@@ -457,6 +470,38 @@ void testNftPageParams() throws JSONException, JsonProcessingException {
assertCanSerializeAndDeserialize(params, json);
}
+ @Test
+ void testDidParams() throws JSONException, JsonProcessingException {
+ LedgerEntryRequestParams params = LedgerEntryRequestParams.did(
+ ED_ADDRESS,
+ LedgerSpecifier.VALIDATED
+ );
+ assertThat(params.did()).isNotEmpty().get().isEqualTo(ED_ADDRESS);
+ assertThat(params.ledgerObjectClass()).isEqualTo(DidObject.class);
+
+ assertThat(params.index()).isEmpty();
+ assertThat(params.accountRoot()).isEmpty();
+ assertThat(params.amm()).isEmpty();
+ assertThat(params.offer()).isEmpty();
+ assertThat(params.rippleState()).isEmpty();
+ assertThat(params.check()).isEmpty();
+ assertThat(params.escrow()).isEmpty();
+ assertThat(params.paymentChannel()).isEmpty();
+ assertThat(params.depositPreAuth()).isEmpty();
+ assertThat(params.ticket()).isEmpty();
+ assertThat(params.nftPage()).isEmpty();
+ assertThat(params.bridgeAccount()).isEmpty();
+ assertThat(params.bridge()).isEmpty();
+
+ String json = String.format("{\n" +
+ " \"did\": \"%s\",\n" +
+ " \"binary\": false,\n" +
+ " \"ledger_index\": \"validated\"\n" +
+ " }", ED_ADDRESS);
+
+ assertCanSerializeAndDeserialize(params, json);
+ }
+
@Test
void testBridgeParams() throws JSONException, JsonProcessingException {
XChainBridge bridge = XChainBridge.builder()
@@ -485,6 +530,7 @@ void testBridgeParams() throws JSONException, JsonProcessingException {
assertThat(params.depositPreAuth()).isEmpty();
assertThat(params.ticket()).isEmpty();
assertThat(params.nftPage()).isEmpty();
+ assertThat(params.did()).isEmpty();
String json = String.format("{\n" +
" \"bridge_account\": \"%s\",\n" +
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/DidObjectTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/DidObjectTest.java
new file mode 100644
index 000000000..4942ee43a
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/ledger/DidObjectTest.java
@@ -0,0 +1,67 @@
+package org.xrpl.xrpl4j.model.ledger;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.DidData;
+import org.xrpl.xrpl4j.model.transactions.DidDocument;
+import org.xrpl.xrpl4j.model.transactions.DidUri;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+
+class DidObjectTest extends AbstractJsonTest {
+
+ @Test
+ void testJsonWithNonEmptyValues() throws JSONException, JsonProcessingException {
+ DidObject object = DidObject.builder()
+ .account(Address.of("rpfqJrXg5uidNo2ZsRhRY6TiF1cvYmV9Fg"))
+ .didDocument(DidDocument.of("646F63"))
+ .data(DidData.of("617474657374"))
+ .ownerNode("0")
+ .previousTransactionId(Hash256.of("A4C15DA185E6092DF5954FF62A1446220C61A5F60F0D93B4B09F708778E41120"))
+ .previousTransactionLedgerSequence(UnsignedInteger.valueOf(4))
+ .uri(DidUri.of("6469645F6578616D706C65"))
+ .index(Hash256.of("46813BE38B798B3752CA590D44E7FEADB17485649074403AD1761A2835CE91FF"))
+ .build();
+
+ String json = "{\n" +
+ " \"Account\": \"rpfqJrXg5uidNo2ZsRhRY6TiF1cvYmV9Fg\",\n" +
+ " \"DIDDocument\": \"646F63\",\n" +
+ " \"Data\": \"617474657374\",\n" +
+ " \"Flags\": 0,\n" +
+ " \"LedgerEntryType\": \"DID\",\n" +
+ " \"OwnerNode\": \"0\",\n" +
+ " \"PreviousTxnID\": \"A4C15DA185E6092DF5954FF62A1446220C61A5F60F0D93B4B09F708778E41120\",\n" +
+ " \"PreviousTxnLgrSeq\": 4,\n" +
+ " \"URI\": \"6469645F6578616D706C65\",\n" +
+ " \"index\": \"46813BE38B798B3752CA590D44E7FEADB17485649074403AD1761A2835CE91FF\"\n" +
+ "}";
+
+ assertCanSerializeAndDeserialize(object, json);
+ }
+
+ @Test
+ void testJsonWithEmptyValues() throws JSONException, JsonProcessingException {
+ DidObject object = DidObject.builder()
+ .account(Address.of("rpfqJrXg5uidNo2ZsRhRY6TiF1cvYmV9Fg"))
+ .ownerNode("0")
+ .previousTransactionId(Hash256.of("A4C15DA185E6092DF5954FF62A1446220C61A5F60F0D93B4B09F708778E41120"))
+ .previousTransactionLedgerSequence(UnsignedInteger.valueOf(4))
+ .index(Hash256.of("46813BE38B798B3752CA590D44E7FEADB17485649074403AD1761A2835CE91FF"))
+ .build();
+
+ String json = "{\n" +
+ " \"Account\": \"rpfqJrXg5uidNo2ZsRhRY6TiF1cvYmV9Fg\",\n" +
+ " \"Flags\": 0,\n" +
+ " \"LedgerEntryType\": \"DID\",\n" +
+ " \"OwnerNode\": \"0\",\n" +
+ " \"PreviousTxnID\": \"A4C15DA185E6092DF5954FF62A1446220C61A5F60F0D93B4B09F708778E41120\",\n" +
+ " \"PreviousTxnLgrSeq\": 4,\n" +
+ " \"index\": \"46813BE38B798B3752CA590D44E7FEADB17485649074403AD1761A2835CE91FF\"\n" +
+ "}";
+
+ assertCanSerializeAndDeserialize(object, json);
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDataTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDataTest.java
new file mode 100644
index 000000000..74650d3aa
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDataTest.java
@@ -0,0 +1,72 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.assertj.core.api.Assertions;
+import org.immutables.value.Value;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.skyscreamer.jsonassert.JSONCompareMode;
+import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory;
+
+public class DidDataTest {
+
+ ObjectMapper objectMapper = ObjectMapperFactory.create();
+
+ @Test
+ void testToString() {
+ DidData count = DidData.of("");
+ assertThat(count.toString()).isEqualTo("");
+
+ DidData countMax = DidData.of("ABCDEFG");
+ assertThat(countMax.toString()).isEqualTo("ABCDEFG");
+ }
+
+ @Test
+ void testJson() throws JsonProcessingException, JSONException {
+ DidData count = DidData.of("ABCDEF");
+ DidDataWrapper wrapper = DidDataWrapper.of(count);
+
+ String json = "{\"value\": \"ABCDEF\"}";
+ assertSerializesAndDeserializes(wrapper, json);
+ }
+
+ @Test
+ void testEmptyValueJson() throws JSONException, JsonProcessingException {
+ DidData count = DidData.of("");
+ DidDataWrapper wrapper = DidDataWrapper.of(count);
+
+ String json = "{\"value\": \"\"}";
+ assertSerializesAndDeserializes(wrapper, json);
+ }
+
+ private void assertSerializesAndDeserializes(
+ DidDataWrapper wrapper,
+ String json
+ ) throws JsonProcessingException, JSONException {
+ String serialized = objectMapper.writeValueAsString(wrapper);
+ JSONAssert.assertEquals(json, serialized, JSONCompareMode.STRICT);
+ DidDataWrapper deserialized = objectMapper.readValue(
+ serialized, DidDataWrapper.class
+ );
+ Assertions.assertThat(deserialized).isEqualTo(wrapper);
+ }
+
+ @Value.Immutable
+ @JsonSerialize(as = ImmutableDidDataWrapper.class)
+ @JsonDeserialize(as = ImmutableDidDataWrapper.class)
+ interface DidDataWrapper {
+
+ static DidDataWrapper of(DidData value) {
+ return ImmutableDidDataWrapper.builder().value(value).build();
+ }
+
+ DidData value();
+
+ }
+}
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDeleteTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDeleteTest.java
new file mode 100644
index 000000000..739963267
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDeleteTest.java
@@ -0,0 +1,72 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+
+class DidDeleteTest extends AbstractJsonTest {
+
+ @Test
+ void testJsonWithEmptyFlags() throws JSONException, JsonProcessingException {
+ DidDelete transaction = baseBuilder().build();
+
+ String json = String.format("{\n" +
+ " \"TransactionType\": \"DIDDelete\", \n" +
+ " \"Account\": \"rp4pqYgrTAtdPHuZd1ZQWxrzx45jxYcZex\",\n" +
+ " \"Fee\": \"12\",\n" +
+ " \"Sequence\": 391,\n" +
+ " \"SigningPubKey\":\"%s\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ @Test
+ void testJsonWithUnsetFlags() throws JSONException, JsonProcessingException {
+ DidDelete transaction = baseBuilder()
+ .flags(TransactionFlags.UNSET)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"TransactionType\": \"DIDDelete\", \n" +
+ " \"Account\": \"rp4pqYgrTAtdPHuZd1ZQWxrzx45jxYcZex\",\n" +
+ " \"Fee\": \"12\",\n" +
+ " \"Sequence\": 391,\n" +
+ " \"Flags\": 0,\n" +
+ " \"SigningPubKey\":\"%s\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ @Test
+ void testJsonWithSetFlags() throws JSONException, JsonProcessingException {
+ DidDelete transaction = baseBuilder()
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"TransactionType\": \"DIDDelete\", \n" +
+ " \"Account\": \"rp4pqYgrTAtdPHuZd1ZQWxrzx45jxYcZex\",\n" +
+ " \"Fee\": \"12\",\n" +
+ " \"Sequence\": 391,\n" +
+ " \"Flags\": %s,\n" +
+ " \"SigningPubKey\":\"%s\"\n" +
+ "}", TransactionFlags.FULLY_CANONICAL_SIG, ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ private ImmutableDidDelete.Builder baseBuilder() {
+ return DidDelete.builder()
+ .account(Address.of("rp4pqYgrTAtdPHuZd1ZQWxrzx45jxYcZex"))
+ .fee(XrpCurrencyAmount.ofDrops(12))
+ .sequence(UnsignedInteger.valueOf(391))
+ .signingPublicKey(ED_PUBLIC_KEY);
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDocumentTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDocumentTest.java
new file mode 100644
index 000000000..0ea670ee7
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidDocumentTest.java
@@ -0,0 +1,73 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.primitives.UnsignedLong;
+import org.assertj.core.api.Assertions;
+import org.immutables.value.Value;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.skyscreamer.jsonassert.JSONCompareMode;
+import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory;
+
+public class DidDocumentTest {
+
+ ObjectMapper objectMapper = ObjectMapperFactory.create();
+
+ @Test
+ void testToString() {
+ DidDocument count = DidDocument.of("");
+ assertThat(count.toString()).isEqualTo("");
+
+ DidDocument countMax = DidDocument.of("ABCDEFG");
+ assertThat(countMax.toString()).isEqualTo("ABCDEFG");
+ }
+
+ @Test
+ void testJson() throws JsonProcessingException, JSONException {
+ DidDocument count = DidDocument.of("ABCDEF");
+ DidDocumentWrapper wrapper = DidDocumentWrapper.of(count);
+
+ String json = "{\"value\": \"ABCDEF\"}";
+ assertSerializesAndDeserializes(wrapper, json);
+ }
+
+ @Test
+ void testEmptyValueJson() throws JSONException, JsonProcessingException {
+ DidDocument count = DidDocument.of("");
+ DidDocumentWrapper wrapper = DidDocumentWrapper.of(count);
+
+ String json = "{\"value\": \"\"}";
+ assertSerializesAndDeserializes(wrapper, json);
+ }
+
+ private void assertSerializesAndDeserializes(
+ DidDocumentWrapper wrapper,
+ String json
+ ) throws JsonProcessingException, JSONException {
+ String serialized = objectMapper.writeValueAsString(wrapper);
+ JSONAssert.assertEquals(json, serialized, JSONCompareMode.STRICT);
+ DidDocumentWrapper deserialized = objectMapper.readValue(
+ serialized, DidDocumentWrapper.class
+ );
+ Assertions.assertThat(deserialized).isEqualTo(wrapper);
+ }
+
+ @Value.Immutable
+ @JsonSerialize(as = ImmutableDidDocumentWrapper.class)
+ @JsonDeserialize(as = ImmutableDidDocumentWrapper.class)
+ interface DidDocumentWrapper {
+
+ static DidDocumentWrapper of(DidDocument value) {
+ return ImmutableDidDocumentWrapper.builder().value(value).build();
+ }
+
+ DidDocument value();
+
+ }
+}
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidSetTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidSetTest.java
new file mode 100644
index 000000000..09051f8c9
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidSetTest.java
@@ -0,0 +1,116 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PUBLIC_KEY;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.primitives.UnsignedInteger;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.AbstractJsonTest;
+import org.xrpl.xrpl4j.model.flags.TransactionFlags;
+
+class DidSetTest extends AbstractJsonTest {
+
+ @Test
+ void testJsonWithNonEmptyFields() throws JSONException, JsonProcessingException {
+ DidSet transaction = DidSet.builder()
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.valueOf(391))
+ .didDocument(DidDocument.of("697066733A2F2F62616679626569676479727A74357366703775646D3768753736756" +
+ "8377932366E6634646675796C71616266336F636C67747179353566627A6469"))
+ .uri(DidUri.of("697066733A2F2F62616679626569676479727A74357366703775646D3768753736756" +
+ "8377932366E6634646675796C71616266336F636C67747179353566627A6469"))
+ .data(DidData.of("697066733A2F2F62616679626569676479727A74357366703775646D3768753736756" +
+ "8377932366E6634646675796C71616266336F636C67747179353566627A6469"))
+ .signingPublicKey(ED_PUBLIC_KEY)
+ .build();
+
+ String json = String.format("{\n" +
+ " \"TransactionType\": \"DIDSet\",\n" +
+ " \"Account\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 391,\n" +
+ " \"DIDDocument\": \"697066733A2F2F62616679626569676479727A74357366703775646D37687537367568377932" +
+ "366E6634646675796C71616266336F636C67747179353566627A6469\",\n" +
+ " \"URI\": \"697066733A2F2F62616679626569676479727A74357366703775646D37687537367568377932366E663464" +
+ "6675796C71616266336F636C67747179353566627A6469\",\n" +
+ " \"Data\": \"697066733A2F2F62616679626569676479727A74357366703775646D37687537367568377932366E66346" +
+ "46675796C71616266336F636C67747179353566627A6469\",\n" +
+ " \"SigningPubKey\":\"%s\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ @Test
+ void testJsonWithEmptyFields() throws JSONException, JsonProcessingException {
+ DidSet transaction = DidSet.builder()
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.valueOf(391))
+ .didDocument(DidDocument.of(""))
+ .uri(DidUri.of(""))
+ .data(DidData.of(""))
+ .signingPublicKey(ED_PUBLIC_KEY)
+ .build();
+ String json = String.format("{\n" +
+ " \"TransactionType\": \"DIDSet\",\n" +
+ " \"Account\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 391,\n" +
+ " \"DIDDocument\": \"\",\n" +
+ " \"URI\": \"\",\n" +
+ " \"Data\": \"\",\n" +
+ " \"SigningPubKey\":\"%s\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ @Test
+ void testJsonWithUnsetFlags() throws JSONException, JsonProcessingException {
+ DidSet transaction = DidSet.builder()
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.valueOf(391))
+ .didDocument(DidDocument.of(""))
+ .flags(TransactionFlags.UNSET)
+ .signingPublicKey(ED_PUBLIC_KEY)
+ .build();
+ String json = String.format("{\n" +
+ " \"TransactionType\": \"DIDSet\",\n" +
+ " \"Account\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 391,\n" +
+ " \"DIDDocument\": \"\",\n" +
+ " \"Flags\": 0,\n" +
+ " \"SigningPubKey\":\"%s\"\n" +
+ "}", ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+
+ @Test
+ void testJsonWithSetFlags() throws JSONException, JsonProcessingException {
+ DidSet transaction = DidSet.builder()
+ .account(Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"))
+ .fee(XrpCurrencyAmount.ofDrops(10))
+ .sequence(UnsignedInteger.valueOf(391))
+ .didDocument(DidDocument.of(""))
+ .flags(TransactionFlags.FULLY_CANONICAL_SIG)
+ .signingPublicKey(ED_PUBLIC_KEY)
+ .build();
+ String json = String.format("{\n" +
+ " \"TransactionType\": \"DIDSet\",\n" +
+ " \"Account\": \"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh\",\n" +
+ " \"Fee\": \"10\",\n" +
+ " \"Sequence\": 391,\n" +
+ " \"DIDDocument\": \"\",\n" +
+ " \"Flags\": %s,\n" +
+ " \"SigningPubKey\":\"%s\"\n" +
+ "}", TransactionFlags.FULLY_CANONICAL_SIG, ED_PUBLIC_KEY.base16Value());
+
+ assertCanSerializeAndDeserialize(transaction, json);
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidUriTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidUriTest.java
new file mode 100644
index 000000000..b2edfbaec
--- /dev/null
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/DidUriTest.java
@@ -0,0 +1,72 @@
+package org.xrpl.xrpl4j.model.transactions;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.assertj.core.api.Assertions;
+import org.immutables.value.Value;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.skyscreamer.jsonassert.JSONCompareMode;
+import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory;
+
+public class DidUriTest {
+
+ ObjectMapper objectMapper = ObjectMapperFactory.create();
+
+ @Test
+ void testToString() {
+ DidUri count = DidUri.of("");
+ assertThat(count.toString()).isEqualTo("");
+
+ DidUri countMax = DidUri.of("ABCDEFG");
+ assertThat(countMax.toString()).isEqualTo("ABCDEFG");
+ }
+
+ @Test
+ void testJson() throws JsonProcessingException, JSONException {
+ DidUri count = DidUri.of("ABCDEF");
+ DidUriWrapper wrapper = DidUriWrapper.of(count);
+
+ String json = "{\"value\": \"ABCDEF\"}";
+ assertSerializesAndDeserializes(wrapper, json);
+ }
+
+ @Test
+ void testEmptyValueJson() throws JSONException, JsonProcessingException {
+ DidUri count = DidUri.of("");
+ DidUriWrapper wrapper = DidUriWrapper.of(count);
+
+ String json = "{\"value\": \"\"}";
+ assertSerializesAndDeserializes(wrapper, json);
+ }
+
+ private void assertSerializesAndDeserializes(
+ DidUriWrapper wrapper,
+ String json
+ ) throws JsonProcessingException, JSONException {
+ String serialized = objectMapper.writeValueAsString(wrapper);
+ JSONAssert.assertEquals(json, serialized, JSONCompareMode.STRICT);
+ DidUriWrapper deserialized = objectMapper.readValue(
+ serialized, DidUriWrapper.class
+ );
+ Assertions.assertThat(deserialized).isEqualTo(wrapper);
+ }
+
+ @Value.Immutable
+ @JsonSerialize(as = ImmutableDidUriWrapper.class)
+ @JsonDeserialize(as = ImmutableDidUriWrapper.class)
+ interface DidUriWrapper {
+
+ static DidUriWrapper of(DidUri value) {
+ return ImmutableDidUriWrapper.builder().value(value).build();
+ }
+
+ DidUri value();
+
+ }
+}
diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryTypeTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryTypeTest.java
index b9c18e6dd..5333b30dd 100644
--- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryTypeTest.java
+++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/metadata/MetaLedgerEntryTypeTest.java
@@ -35,6 +35,7 @@ void testConstants() {
assertThat(MetaLedgerEntryType.XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID.value())
.isEqualTo("XChainOwnedCreateAccountClaimID");
assertThat(MetaLedgerEntryType.XCHAIN_OWNED_CLAIM_ID.value()).isEqualTo("XChainOwnedClaimID");
+ assertThat(MetaLedgerEntryType.DID.value()).isEqualTo("DID");
}
@Test
@@ -62,6 +63,7 @@ void testLedgerObjectType() {
assertThat(MetaLedgerEntryType.XCHAIN_OWNED_CLAIM_ID.ledgerObjectType()).isEqualTo(
MetaXChainOwnedClaimIdObject.class
);
+ assertThat(MetaLedgerEntryType.DID.ledgerObjectType()).isEqualTo(MetaDidObject.class);
}
@Test
diff --git a/xrpl4j-core/src/test/resources/codec-fixtures.json b/xrpl4j-core/src/test/resources/codec-fixtures.json
index b9a43d13c..28f7946f9 100644
--- a/xrpl4j-core/src/test/resources/codec-fixtures.json
+++ b/xrpl4j-core/src/test/resources/codec-fixtures.json
@@ -5019,6 +5019,33 @@
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
"TxnSignature": "BC2F6E76969E3747E9BDE183C97573B086212F09D5387460E6EE2F32953E85EAEB9618FBBEF077276E30E59D619FCF7C7BDCDDDD9EB94D7CE1DD5CE9246B2107"
}
+ },
+ {
+ "binary": "1200322280000000240000000468400000000000000A7321ED9861C4CB029C0DA737B823D7D3459A70F227958D5C0C111CC7CF947FC5A93347744071E28B12465A1B47162C22E121DF61089DCD9AAF5773704B76179E771666886C8AAD5A33A87E34CC381A7D924E3FE3645F0BF98D565DE42C81E1A7A7E7981802811401476926B590BA3245F63C829116A0A3AF7F382D",
+ "json": {
+ "Account": "rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8",
+ "Fee": "10",
+ "Flags": 2147483648,
+ "Sequence": 4,
+ "SigningPubKey": "ED9861C4CB029C0DA737B823D7D3459A70F227958D5C0C111CC7CF947FC5A93347",
+ "TransactionType": "DIDDelete",
+ "TxnSignature": "71E28B12465A1B47162C22E121DF61089DCD9AAF5773704B76179E771666886C8AAD5A33A87E34CC381A7D924E3FE3645F0BF98D565DE42C81E1A7A7E7981802"
+ }
+ },
+ {
+ "binary": "1200312280000000240000000368400000000000000A7321ED9861C4CB029C0DA737B823D7D3459A70F227958D5C0C111CC7CF947FC5A933477440AACD31A04CAE14670FC483A1382F393AA96B49C84479B58067F049FBD772999325667A6AA2520A63756EE84F3657298815019DD56A1AECE796B08535C4009C08750B6469645F6578616D706C65701A03646F63701B06617474657374811401476926B590BA3245F63C829116A0A3AF7F382D",
+ "json": {
+ "Account": "rfmDuhDyLGgx94qiwf3YF8BUV5j6KSvE8",
+ "Data": "617474657374",
+ "DIDDocument": "646F63",
+ "Fee": "10",
+ "Flags": 2147483648,
+ "Sequence": 3,
+ "SigningPubKey": "ED9861C4CB029C0DA737B823D7D3459A70F227958D5C0C111CC7CF947FC5A93347",
+ "TransactionType": "DIDSet",
+ "TxnSignature": "AACD31A04CAE14670FC483A1382F393AA96B49C84479B58067F049FBD772999325667A6AA2520A63756EE84F3657298815019DD56A1AECE796B08535C4009C08",
+ "URI": "6469645F6578616D706C65"
+ }
}
],
"ledgerData": [
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/DidIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/DidIT.java
new file mode 100644
index 000000000..fcd886e17
--- /dev/null
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/DidIT.java
@@ -0,0 +1,270 @@
+package org.xrpl.xrpl4j.tests;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.primitives.UnsignedInteger;
+import org.immutables.value.Value.Immutable;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIf;
+import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
+import org.xrpl.xrpl4j.crypto.keys.KeyPair;
+import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
+import org.xrpl.xrpl4j.model.client.accounts.AccountObjectsResult;
+import org.xrpl.xrpl4j.model.client.common.LedgerSpecifier;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
+import org.xrpl.xrpl4j.model.client.ledger.LedgerEntryRequestParams;
+import org.xrpl.xrpl4j.model.client.ledger.LedgerEntryResult;
+import org.xrpl.xrpl4j.model.client.transactions.TransactionResult;
+import org.xrpl.xrpl4j.model.flags.Flags;
+import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory;
+import org.xrpl.xrpl4j.model.ledger.DidObject;
+import org.xrpl.xrpl4j.model.ledger.LedgerObject;
+import org.xrpl.xrpl4j.model.transactions.DidData;
+import org.xrpl.xrpl4j.model.transactions.DidDelete;
+import org.xrpl.xrpl4j.model.transactions.DidDocument;
+import org.xrpl.xrpl4j.model.transactions.DidSet;
+import org.xrpl.xrpl4j.model.transactions.DidUri;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+import org.xrpl.xrpl4j.model.transactions.metadata.CreatedNode;
+import org.xrpl.xrpl4j.model.transactions.metadata.DeletedNode;
+import org.xrpl.xrpl4j.model.transactions.metadata.MetaDidObject;
+import org.xrpl.xrpl4j.model.transactions.metadata.MetaLedgerEntryType;
+import org.xrpl.xrpl4j.model.transactions.metadata.ModifiedNode;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@DisabledIf(value = "shouldRun", disabledReason = "DidIT only runs with local rippled nodes.")
+public class DidIT extends AbstractIT {
+
+ static boolean shouldRun() {
+ return System.getProperty("useTestnet") != null ||
+ System.getProperty("useDevnet") != null ||
+ System.getProperty("useClioTestnet") != null;
+ }
+
+ @Test
+ void testCreateAndUpdateDid() throws JsonRpcClientErrorException, JsonProcessingException {
+ TestDid did = createNewDid();
+
+ AccountInfoResult sourceAccountInfo = this.getValidatedAccountInfo(
+ did.ownerKeyPair().publicKey().deriveAddress());
+
+ XrpCurrencyAmount fee = FeeUtils.computeNetworkFees(xrplClient.fee()).recommendedFee();
+ DidSet updateDid = DidSet.builder()
+ .account(did.ownerKeyPair().publicKey().deriveAddress())
+ .sequence(sourceAccountInfo.accountData().sequence())
+ .fee(fee)
+ .lastLedgerSequence(sourceAccountInfo.ledgerIndexSafe().plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue())
+ .signingPublicKey(did.ownerKeyPair().publicKey())
+ .didDocument(DidDocument.of(""))
+ .uri(DidUri.of("ABCD"))
+ .build();
+
+ TransactionResult didSetResult = this.signSubmitAndWait(
+ updateDid,
+ did.ownerKeyPair(),
+ DidSet.class
+ );
+
+ assertThat(didSetResult.metadata()).isNotEmpty();
+ List> modifiedNodes = didSetResult.metadata().get().affectedNodes().stream()
+ .filter(node -> node.ledgerEntryType().equals(MetaLedgerEntryType.DID))
+ .filter(node -> ModifiedNode.class.isAssignableFrom(node.getClass()))
+ .filter(node -> MetaDidObject.class.isAssignableFrom(((ModifiedNode>) node).finalFields().get().getClass()))
+ .filter(node -> MetaDidObject.class.isAssignableFrom(((ModifiedNode>) node).previousFields().get().getClass()))
+ .map(node -> (ModifiedNode) node)
+ .collect(Collectors.toList());
+
+ assertThat(modifiedNodes.size()).isEqualTo(1);
+ ModifiedNode modifiedNode = modifiedNodes.get(0);
+ assertThat(modifiedNode.previousFields()).isNotEmpty();
+ MetaDidObject previousFields = modifiedNode.previousFields().get();
+ assertThat(previousFields.didDocument()).isNotEmpty().isEqualTo(did.object().didDocument());
+ assertThat(previousFields.uri()).isNotEmpty().isEqualTo(did.object().uri());
+ assertThat(previousFields.data()).isEmpty();
+ assertThat(previousFields.account()).isEmpty();
+ assertThat(previousFields.flags()).isEqualTo(Flags.UNSET);
+
+ assertThat(modifiedNode.previousFields()).isNotEmpty();
+ MetaDidObject finalFields = modifiedNode.finalFields().get();
+ assertThat(finalFields.didDocument()).isEmpty();
+ assertThat(finalFields.uri()).isNotEmpty().isEqualTo(updateDid.uri());
+ assertThat(finalFields.data()).isNotEmpty().isEqualTo(did.object().data());
+ assertThat(finalFields.account()).isNotEmpty().get().isEqualTo(sourceAccountInfo.accountData().account());
+ assertThat(finalFields.flags()).isEqualTo(Flags.UNSET);
+
+ List accountObjects = this.getValidatedAccountObjects(
+ did.ownerKeyPair().publicKey().deriveAddress(),
+ DidObject.class
+ );
+ assertThat(accountObjects.size()).isEqualTo(1);
+ DidObject didFromAccountObjects = accountObjects.get(0);
+ assertThat(didFromAccountObjects.account()).isEqualTo(sourceAccountInfo.accountData().account());
+ assertThat(didFromAccountObjects.didDocument()).isEmpty();
+ assertThat(didFromAccountObjects.uri()).isNotEmpty().isEqualTo(updateDid.uri());
+ assertThat(didFromAccountObjects.data()).isNotEmpty().isEqualTo(did.object().data());
+ assertThat(didFromAccountObjects.flags()).isEqualTo(did.object().flags());
+
+ LedgerEntryResult didFromLedgerEntryIndex = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ modifiedNode.ledgerIndex(),
+ DidObject.class,
+ LedgerSpecifier.VALIDATED
+ )
+ );
+
+ assertThat(didFromLedgerEntryIndex.node()).isEqualTo(didFromAccountObjects);
+
+ LedgerEntryResult didFromLedgerEntry = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.did(
+ did.ownerKeyPair().publicKey().deriveAddress(),
+ LedgerSpecifier.VALIDATED
+ )
+ );
+
+ assertThat(didFromLedgerEntry.node()).isEqualTo(didFromAccountObjects);
+ }
+
+ @Test
+ void testCreateAndDeleteDid() throws JsonRpcClientErrorException, JsonProcessingException {
+ TestDid did = createNewDid();
+
+ AccountInfoResult sourceAccountInfo = this.getValidatedAccountInfo(
+ did.ownerKeyPair().publicKey().deriveAddress());
+
+ XrpCurrencyAmount fee = FeeUtils.computeNetworkFees(xrplClient.fee()).recommendedFee();
+ DidDelete didDelete = DidDelete.builder()
+ .account(did.ownerKeyPair().publicKey().deriveAddress())
+ .sequence(sourceAccountInfo.accountData().sequence())
+ .fee(fee)
+ .lastLedgerSequence(sourceAccountInfo.ledgerIndexSafe().plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue())
+ .signingPublicKey(did.ownerKeyPair().publicKey())
+ .build();
+
+ TransactionResult result = this.signSubmitAndWait(didDelete, did.ownerKeyPair(), DidDelete.class);
+
+ logger.info(ObjectMapperFactory.create().writerWithDefaultPrettyPrinter().writeValueAsString(result));
+ assertThat(result.metadata()).isNotEmpty();
+ List> deletedNodes = result.metadata().get().affectedNodes().stream()
+ .filter(node -> node.ledgerEntryType().equals(MetaLedgerEntryType.DID))
+ .filter(node -> DeletedNode.class.isAssignableFrom(node.getClass()))
+ .filter(node -> MetaDidObject.class.isAssignableFrom(((DeletedNode>) node).finalFields().getClass()))
+ .map(node -> (DeletedNode) node)
+ .collect(Collectors.toList());
+
+ assertThat(deletedNodes.size()).isEqualTo(1);
+ DeletedNode deletedNode = deletedNodes.get(0);
+ MetaDidObject finalFields = deletedNode.finalFields();
+ assertThat(finalFields.didDocument()).isNotEmpty().isEqualTo(did.object().didDocument());
+ assertThat(finalFields.uri()).isNotEmpty().isEqualTo(did.object().uri());
+ assertThat(finalFields.data()).isNotEmpty().isEqualTo(did.object().data());
+ assertThat(finalFields.account()).isNotEmpty().get().isEqualTo(sourceAccountInfo.accountData().account());
+ assertThat(finalFields.flags()).isEqualTo(Flags.UNSET);
+
+ List accountObjects = this.getValidatedAccountObjects(
+ sourceAccountInfo.accountData().account(),
+ DidObject.class
+ );
+
+ assertThat(accountObjects).asList().isEmpty();
+ }
+
+ private TestDid createNewDid() throws JsonRpcClientErrorException, JsonProcessingException {
+ KeyPair sourceKeyPair = this.createRandomAccountEd25519();
+
+ AccountInfoResult sourceAccountInfo = this.scanForResult(
+ () -> this.getValidatedAccountInfo(sourceKeyPair.publicKey().deriveAddress())
+ );
+
+ XrpCurrencyAmount fee = FeeUtils.computeNetworkFees(xrplClient.fee()).recommendedFee();
+
+ DidSet didSet = DidSet.builder()
+ .account(sourceAccountInfo.accountData().account())
+ .sequence(sourceAccountInfo.accountData().sequence())
+ .fee(fee)
+ .lastLedgerSequence(sourceAccountInfo.ledgerIndexSafe().unsignedIntegerValue().plus(UnsignedInteger.valueOf(4)))
+ .signingPublicKey(sourceKeyPair.publicKey())
+ .data(DidData.of("617474657374"))
+ .uri(DidUri.of("6469645F6578616D706C65"))
+ .didDocument(DidDocument.of("646F63"))
+ .build();
+
+ TransactionResult didSetResult = this.signSubmitAndWait(didSet, sourceKeyPair, DidSet.class);
+ assertThat(didSetResult.metadata()).isNotEmpty();
+ List> createdNodes = didSetResult.metadata().get().affectedNodes().stream()
+ .filter(node -> node.ledgerEntryType().equals(MetaLedgerEntryType.DID))
+ .filter(node -> CreatedNode.class.isAssignableFrom(node.getClass()))
+ .filter(node -> MetaDidObject.class.isAssignableFrom(((CreatedNode>) node).newFields().getClass()))
+ .map(node -> (CreatedNode) node)
+ .collect(Collectors.toList());
+
+ assertThat(createdNodes.size()).isEqualTo(1);
+ CreatedNode createdNode = createdNodes.get(0);
+ MetaDidObject createdDid = createdNode.newFields();
+ assertThat(createdDid.didDocument()).isNotEmpty().isEqualTo(didSet.didDocument());
+ assertThat(createdDid.uri()).isNotEmpty().isEqualTo(didSet.uri());
+ assertThat(createdDid.data()).isNotEmpty().isEqualTo(didSet.data());
+ assertThat(createdDid.account()).isNotEmpty().get().isEqualTo(sourceAccountInfo.accountData().account());
+ assertThat(createdDid.flags()).isEqualTo(Flags.UNSET);
+
+ List accountObjects = this.getValidatedAccountObjects(
+ sourceKeyPair.publicKey().deriveAddress(),
+ DidObject.class
+ );
+ assertThat(accountObjects.size()).isEqualTo(1);
+ DidObject didFromAccountObjects = accountObjects.get(0);
+ assertThat(didFromAccountObjects.account()).isEqualTo(sourceAccountInfo.accountData().account());
+ assertThat(didFromAccountObjects.didDocument()).isNotEmpty().isEqualTo(createdDid.didDocument());
+ assertThat(didFromAccountObjects.uri()).isNotEmpty().isEqualTo(createdDid.uri());
+ assertThat(didFromAccountObjects.data()).isNotEmpty().isEqualTo(createdDid.data());
+ assertThat(didFromAccountObjects.flags()).isEqualTo(createdDid.flags());
+
+ LedgerEntryResult didFromLedgerEntryIndex = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.index(
+ createdNode.ledgerIndex(),
+ DidObject.class,
+ LedgerSpecifier.VALIDATED
+ )
+ );
+
+ assertThat(didFromLedgerEntryIndex.node()).isEqualTo(didFromAccountObjects);
+
+ LedgerEntryResult didFromLedgerEntry = xrplClient.ledgerEntry(
+ LedgerEntryRequestParams.did(
+ sourceKeyPair.publicKey().deriveAddress(),
+ LedgerSpecifier.VALIDATED
+ )
+ );
+
+ assertThat(didFromLedgerEntry.node()).isEqualTo(didFromAccountObjects);
+
+ return TestDid.builder()
+ .object(didFromLedgerEntry.node())
+ .ownerKeyPair(sourceKeyPair)
+ .build();
+ }
+
+ @Immutable
+ @JsonSerialize(as = ImmutableTestDid.class)
+ @JsonDeserialize(as = ImmutableTestDid.class)
+ interface TestDid {
+
+ /**
+ * Construct a {@code TestDid} builder.
+ *
+ * @return An {@link ImmutableTestDid.Builder}.
+ */
+ static ImmutableTestDid.Builder builder() {
+ return ImmutableTestDid.builder();
+ }
+
+ KeyPair ownerKeyPair();
+
+ DidObject object();
+
+ }
+}
From 24bf9962d2a13c4a197837478a1bf35324a41fd5 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 4 Dec 2023 16:25:35 -0500
Subject: [PATCH 3/4] Bump ch.qos.logback:logback-classic from 1.4.11 to 1.4.12
(#504)
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.11 to 1.4.12.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.4.11...v_1.4.12)
---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
dependency-type: direct:development
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: nkramer44
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index d75c33d72..82577648f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,7 +69,7 @@
ch.qos.logback
logback-classic
- 1.4.11
+ 1.4.12
org.assertj
From 3c4a07692e8debf1aacb7ef924a47d8c8b2e07fa Mon Sep 17 00:00:00 2001
From: nkramer44
Date: Wed, 6 Dec 2023 13:23:27 -0500
Subject: [PATCH 4/4] Revert logback-classic to 1.3.X to work with JDK 8 (#509)
revert logback-classic to 1.3.X to work with jdk 8
---
pom.xml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index 82577648f..938e8b369 100644
--- a/pom.xml
+++ b/pom.xml
@@ -66,10 +66,11 @@
jackson-datatype-cryptoconditions
${cryptoconditions.version}
+
ch.qos.logback
logback-classic
- 1.4.12
+ 1.3.8
org.assertj
@@ -291,7 +292,7 @@
1.0.4
2.14.2
12.3
- 1.7.36
+ 2.0.7
5.10.0
32.1.1-jre