signerListSetResult = xrplClient.submit(sourceWallet, signerListSet);
assertThat(signerListSetResult.result()).isEqualTo(TransactionResultCodes.TES_SUCCESS);
assertThat(signerListSetResult.transactionResult().transaction().hash()).isNotEmpty().get()
- .isEqualTo(signerListSetResult.transactionResult().hash());
+ .isEqualTo(signerListSetResult.transactionResult().hash());
logger.info(
"SignerListSet transaction successful: https://testnet.xrpl.org/transactions/" +
signerListSetResult.transactionResult().hash()
@@ -138,7 +140,7 @@ void addSignersToSignerListAndSendPayment() throws JsonRpcClientErrorException {
Payment unsignedPayment = Payment.builder()
.account(sourceWallet.classicAddress())
.fee(
- Transaction.computeMultiSigFee(
+ FeeUtils.computeMultiSigFee(
feeResult.drops().openLedgerFee(),
sourceAccountInfoAfterSignerListSet.accountData().signerLists().get(0)
)
@@ -214,7 +216,7 @@ void addSignersToSignerListThenDeleteSignerList() throws JsonRpcClientErrorExcep
FeeResult feeResult = xrplClient.fee();
SignerListSet signerListSet = SignerListSet.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.calculateFeeDynamically(feeResult))
.sequence(sourceAccountInfo.accountData().sequence())
.signerQuorum(UnsignedInteger.valueOf(2))
.addSignerEntries(
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitMultisignedIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitMultisignedIT.java
index e3a05f496..47f687e78 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitMultisignedIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitMultisignedIT.java
@@ -15,6 +15,7 @@
import org.xrpl.xrpl4j.keypairs.KeyPairService;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SignedTransaction;
import org.xrpl.xrpl4j.model.client.transactions.SubmitMultiSignedResult;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
@@ -75,7 +76,7 @@ public void setUp() throws JsonRpcClientErrorException {
feeResult = xrplClient.fee();
SignerListSet signerListSet = SignerListSet.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.calculateFeeDynamically(feeResult))
.sequence(sourceAccountInfo.accountData().sequence())
.signerQuorum(UnsignedInteger.valueOf(2))
.addSignerEntries(
@@ -132,7 +133,7 @@ public void submitMultisignedAndVerifyHash() throws JsonRpcClientErrorException,
Payment unsignedPayment = Payment.builder()
.account(sourceWallet.classicAddress())
.fee(
- Transaction.computeMultiSigFee(
+ FeeUtils.computeMultiSigFee(
feeResult.drops().openLedgerFee(),
sourceAccountInfoAfterSignerListSet.accountData().signerLists().get(0)
)
@@ -201,7 +202,7 @@ public void submitMultisignedWithSignersInDescOrderAndVerifyHash() throws
Payment unsignedPayment = Payment.builder()
.account(sourceWallet.classicAddress())
.fee(
- Transaction.computeMultiSigFee(
+ FeeUtils.computeMultiSigFee(
feeResult.drops().openLedgerFee(),
sourceAccountInfoAfterSignerListSet.accountData().signerLists().get(0)
)
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitPaymentIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitPaymentIT.java
index ad712fe9d..9f38b320d 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitPaymentIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitPaymentIT.java
@@ -27,6 +27,7 @@
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
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.LedgerRequestParams;
import org.xrpl.xrpl4j.model.client.ledger.LedgerResult;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
@@ -50,7 +51,7 @@ public void sendPayment() throws JsonRpcClientErrorException {
XrpCurrencyAmount amount = XrpCurrencyAmount.ofDrops(12345);
Payment payment = Payment.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.calculateFeeDynamically(feeResult))
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.classicAddress())
.amount(amount)
@@ -93,7 +94,7 @@ public void sendPaymentFromSecp256k1Wallet() throws JsonRpcClientErrorException
Payment payment = Payment.builder()
.account(senderWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.calculateFeeDynamically(feeResult))
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.classicAddress())
.amount(XrpCurrencyAmount.ofDrops(12345))
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TicketIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TicketIT.java
index f4a89fa18..29e31572b 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TicketIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TicketIT.java
@@ -27,6 +27,7 @@
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.ledger.TicketObject;
import org.xrpl.xrpl4j.model.transactions.AccountSet;
@@ -49,7 +50,7 @@ void createTicketAndUseSequenceNumber() throws JsonRpcClientErrorException {
TicketCreate ticketCreate = TicketCreate.builder()
.account(sourceWallet.classicAddress())
.sequence(accountInfo.accountData().sequence())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.calculateFeeDynamically(feeResult))
.ticketCount(UnsignedInteger.ONE)
.signingPublicKey(sourceWallet.publicKey())
.build();
@@ -71,7 +72,7 @@ void createTicketAndUseSequenceNumber() throws JsonRpcClientErrorException {
AccountSet accountSet = AccountSet.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.calculateFeeDynamically(feeResult))
.ticketSequence(tickets.get(0).ticketSequence())
.signingPublicKey(sourceWallet.publicKey())
.build();
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TransactionWithMemoIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TransactionWithMemoIT.java
index 1575c0615..8456d5a57 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TransactionWithMemoIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TransactionWithMemoIT.java
@@ -26,6 +26,7 @@
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.client.transactions.TransactionResult;
import org.xrpl.xrpl4j.model.transactions.Memo;
@@ -51,7 +52,7 @@ public void transactionWithMemoNibble() throws JsonRpcClientErrorException {
XrpCurrencyAmount amount = XrpCurrencyAmount.ofDrops(12345);
Payment payment = Payment.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.calculateFeeDynamically(feeResult))
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.classicAddress())
.amount(amount)
@@ -96,7 +97,7 @@ public void transactionWithPlaintextMemo() throws JsonRpcClientErrorException {
XrpCurrencyAmount amount = XrpCurrencyAmount.ofDrops(12345);
Payment payment = Payment.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.calculateFeeDynamically(feeResult))
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.classicAddress())
.amount(amount)
diff --git a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeUtils.java b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeUtils.java
new file mode 100644
index 000000000..9fe1fa631
--- /dev/null
+++ b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeUtils.java
@@ -0,0 +1,94 @@
+package org.xrpl.xrpl4j.model.client.fees;
+
+import com.google.common.primitives.UnsignedLong;
+import org.xrpl.xrpl4j.model.ledger.SignerListObject;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+import java.util.Objects;
+
+public class FeeUtils {
+
+ /**
+ * Computes the fee necessary for a multisigned transaction.
+ *
+ * The transaction cost of a multisigned transaction must be at least {@code (N + 1) * (the normal
+ * transaction cost)}, where {@code N} is the number of signatures provided.
+ *
+ * @param currentLedgerFeeDrops The current ledger fee, represented as an {@link XrpCurrencyAmount}.
+ * @param signerList The {@link SignerListObject} containing the signers of the transaction.
+ *
+ * @return An {@link XrpCurrencyAmount} representing the multisig fee.
+ */
+ public static XrpCurrencyAmount computeMultiSigFee(
+ final XrpCurrencyAmount currentLedgerFeeDrops,
+ final SignerListObject signerList
+ ) {
+ Objects.requireNonNull(currentLedgerFeeDrops);
+ Objects.requireNonNull(signerList);
+
+ return currentLedgerFeeDrops
+ .times(XrpCurrencyAmount.of(UnsignedLong.valueOf(signerList.signerEntries().size() + 1)));
+ }
+
+
+ /**
+ * Get value of fee to be used for submitting a transaction on the ledger. The value is calculated depending on the
+ * load on the job queue.
+ *
+ * @param feeResult {@link FeeResult} object received from XrplClient#fee() rippled call.
+ *
+ * @return {@link XrpCurrencyAmount} value of the fee that should be used for the transaction.
+ */
+ public static XrpCurrencyAmount calculateFeeDynamically(final FeeResult feeResult) {
+ Objects.requireNonNull(feeResult);
+
+ double currentQueueSize = feeResult.currentQueueSize().doubleValue();
+ double maxQueueSize = feeResult.maxQueueSize().get().doubleValue();
+ double queuePercentage = currentQueueSize / maxQueueSize;
+ FeeDrops drops = feeResult.drops();
+ int minimumFee = drops.minimumFee().value().intValue();
+ int medianFee = drops.medianFee().value().intValue();
+ int openLedgerFee = drops.openLedgerFee().value().intValue();
+
+ // calculate the lowest fee the user is able to pay if the queue is empty
+ final long feeLow = Math.round(
+ Math.min(
+ Math.max(
+ minimumFee * 1.5,
+ Math.round(Math.max(medianFee, openLedgerFee) / 500)
+ ),
+ 1000
+ )
+ );
+
+ long possibleFeeMedium;
+ if (queuePercentage > 0.1) {
+ possibleFeeMedium = Math.round((minimumFee + openLedgerFee) / 3);
+ } else if (queuePercentage == 0) {
+ possibleFeeMedium = Math.max(10 * minimumFee, openLedgerFee);
+ } else {
+ possibleFeeMedium = Math.max(10 * minimumFee, Math.round((minimumFee + medianFee) / 2));
+ }
+
+ // calculate the lowest fee the user is able to pay if there are txns in the queue
+ final long feeMedium = Math.round(Math.min(possibleFeeMedium, Math.min((int) (feeLow * 15), 10000)));
+
+ // calculate the lowest fee the user is able to pay if the txn queue is full
+ final long feeHigh = Math.round(Math.min(
+ Math.max(10 * minimumFee, Math.round(Math.max(medianFee, openLedgerFee) * 1.1)),
+ 100000
+ ));
+
+ XrpCurrencyAmount fee;
+ if (queuePercentage == 0) { // if queue is empty
+ fee = XrpCurrencyAmount.ofDrops(feeLow);
+ } else if (0 < queuePercentage && queuePercentage < 1) { // queue has txns in it but is not full
+ fee = XrpCurrencyAmount.ofDrops(feeMedium);
+ } else { // if queue is full
+ fee = XrpCurrencyAmount.ofDrops(feeHigh);
+ }
+
+ return fee;
+ }
+
+}
diff --git a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java
index 528dbb4fa..e55fc71f3 100644
--- a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java
+++ b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.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.
@@ -95,6 +95,7 @@ public interface Transaction {
*
* @return An {@link XrpCurrencyAmount} representing the multisig fee.
*/
+ @Deprecated
static XrpCurrencyAmount computeMultiSigFee(
final XrpCurrencyAmount currentLedgerFeeDrops,
final SignerListObject signerList
@@ -232,7 +233,7 @@ default UnsignedInteger sequence() {
*
* @return An optionally-present {@link UnsignedLong}.
* @deprecated This field will be removed in favor of {@link
- * org.xrpl.xrpl4j.model.client.transactions.TransactionResult#closeDate()};
+ * org.xrpl.xrpl4j.model.client.transactions.TransactionResult#closeDate()};
*/
@JsonProperty("date")
@Deprecated
diff --git a/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/FeeUtilsTest.java b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/FeeUtilsTest.java
new file mode 100644
index 000000000..8e934e76b
--- /dev/null
+++ b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/FeeUtilsTest.java
@@ -0,0 +1,224 @@
+package org.xrpl.xrpl4j.model.client.fees;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.xrpl.xrpl4j.model.client.fees.FeeUtils.calculateFeeDynamically;
+import static org.xrpl.xrpl4j.model.client.fees.FeeUtils.computeMultiSigFee;
+
+import com.google.common.primitives.UnsignedInteger;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.client.common.LedgerIndex;
+import org.xrpl.xrpl4j.model.flags.Flags;
+import org.xrpl.xrpl4j.model.ledger.SignerEntry;
+import org.xrpl.xrpl4j.model.ledger.SignerEntryWrapper;
+import org.xrpl.xrpl4j.model.ledger.SignerListObject;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+/**
+ * Unit tests for {@link FeeUtils}.
+ */
+public class FeeUtilsTest {
+
+ @Test
+ public void nullInputForComputeMultiSigFee() {
+ assertThrows(
+ NullPointerException.class,
+ () -> computeMultiSigFee(null, null)
+ );
+
+ assertThrows(
+ NullPointerException.class,
+ () -> computeMultiSigFee(XrpCurrencyAmount.ofDrops(20), null)
+ );
+ }
+
+ @Test
+ public void simpleComputeMultiSigFee() {
+ XrpCurrencyAmount xrpCurrencyAmount = XrpCurrencyAmount.ofDrops(20);
+ SignerListObject object = SignerListObject.builder()
+ .flags(Flags.SignerListFlags.UNSET)
+ .ownerNode("0000000000000000")
+ .previousTransactionId(Hash256.of("5904C0DC72C58A83AEFED2FFC5386356AA83FCA6A88C89D00646E51E687CDBE4"))
+ .previousTransactionLedgerSequence(UnsignedInteger.valueOf(16061435))
+ .addSignerEntries(
+ SignerEntryWrapper.of(
+ SignerEntry.builder()
+ .account(Address.of("rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW"))
+ .signerWeight(UnsignedInteger.valueOf(2))
+ .build()
+ ),
+ SignerEntryWrapper.of(
+ SignerEntry.builder()
+ .account(Address.of("raKEEVSGnKSD9Zyvxu4z6Pqpm4ABH8FS6n"))
+ .signerWeight(UnsignedInteger.valueOf(1))
+ .build()
+ )
+ )
+ .signerListId(UnsignedInteger.ZERO)
+ .signerQuorum(UnsignedInteger.valueOf(3))
+ .index(Hash256.of("A9C28A28B85CD533217F5C0A0C7767666B093FA58A0F2D80026FCC4CD932DDC7"))
+ .build();
+
+ assertThat(computeMultiSigFee(xrpCurrencyAmount, object)).isEqualTo(XrpCurrencyAmount.ofDrops(60));
+ }
+
+ @Test
+ public void nullInputForCalculateFeeDynamically() {
+ assertThrows(
+ NullPointerException.class,
+ () -> calculateFeeDynamically(null)
+ );
+ }
+
+ @Test
+ public void calculateFeeDynamicallyForAlmostEmptyQueue() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(1))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(10000))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2653937))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(1100))
+ .status("success")
+ .build();
+
+ assertThat(calculateFeeDynamically(feeResult)).isEqualTo(XrpCurrencyAmount.ofDrops(5005));
+ }
+
+ @Test
+ public void calculateFeeDynamicallyForModeratelyFilledQueue() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(220))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(10000))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2653937))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(1100))
+ .status("success")
+ .build();
+
+ assertThat(calculateFeeDynamically(feeResult)).isEqualTo(XrpCurrencyAmount.ofDrops(10000));
+ }
+
+ @Test
+ public void calculateFeeDynamicallyForLessThanModerateTraffic() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(100))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(10000))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2653937))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(1100))
+ .status("success")
+ .build();
+
+ assertThat(calculateFeeDynamically(feeResult)).isEqualTo(XrpCurrencyAmount.ofDrops(5005));
+ }
+
+ @Test
+ public void calculateFeeDynamicallyForCompletelyFilledQueue() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(110))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(100))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2657))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(110))
+ .status("success")
+ .build();
+
+ assertThat(calculateFeeDynamically(feeResult)).isEqualTo(XrpCurrencyAmount.ofDrops(2923));
+ }
+
+ @Test
+ public void calculateFeeDynamicallyForEmptyQueue() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(0))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(100))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2657))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(110))
+ .status("success")
+ .build();
+
+ assertThat(calculateFeeDynamically(feeResult)).isEqualTo(XrpCurrencyAmount.ofDrops(15));
+ }
+}
From f38c2ebcd5af69c1dafe9b3c1aff72e5ebc3b77a Mon Sep 17 00:00:00 2001
From: David Fuelling
Date: Thu, 23 Jun 2022 08:37:07 -0600
Subject: [PATCH 08/12] Update Javadoc
Signed-off-by: David Fuelling
---
.../java/org/xrpl/xrpl4j/crypto/bc/BcAddressUtils.java | 4 ++++
.../java/org/xrpl/xrpl4j/crypto/core/AddressUtils.java | 8 ++++++++
2 files changed, 12 insertions(+)
diff --git a/xrpl4j-crypto-parent/xrpl4j-crypto-bouncycastle/src/main/java/org/xrpl/xrpl4j/crypto/bc/BcAddressUtils.java b/xrpl4j-crypto-parent/xrpl4j-crypto-bouncycastle/src/main/java/org/xrpl/xrpl4j/crypto/bc/BcAddressUtils.java
index 9dc6c9c88..6ea08b32c 100644
--- a/xrpl4j-crypto-parent/xrpl4j-crypto-bouncycastle/src/main/java/org/xrpl/xrpl4j/crypto/bc/BcAddressUtils.java
+++ b/xrpl4j-crypto-parent/xrpl4j-crypto-bouncycastle/src/main/java/org/xrpl/xrpl4j/crypto/bc/BcAddressUtils.java
@@ -12,7 +12,11 @@
/**
* A service to help with interactions involving XRPL addresses.
+ *
+ * @deprecated This interface will be removed in a future version. Prefer
+ * {@link org.xrpl.xrpl4j.crypto.core.keys.KeyPairService} instead.
*/
+@Deprecated
public class BcAddressUtils implements AddressUtils {
private static final BcAddressUtils INSTANCE = new BcAddressUtils();
diff --git a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/AddressUtils.java b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/AddressUtils.java
index 9353c14c2..0ee5f5827 100644
--- a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/AddressUtils.java
+++ b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/AddressUtils.java
@@ -5,7 +5,11 @@
/**
* A utility interface to help with interactions involving XRPL addresses.
+ *
+ * @deprecated This interface will be removed in a future version. Prefer
+ * {@link org.xrpl.xrpl4j.crypto.core.keys.KeyPairService} instead.
*/
+@Deprecated
public interface AddressUtils {
/**
@@ -14,7 +18,11 @@ public interface AddressUtils {
* @param publicKey The hexadecimal encoded public key of the account.
*
* @return A Base58Check encoded XRPL address in Classic Address form.
+ *
+ * @deprecated This interface will be removed in a future version. Prefer
+ * {@link org.xrpl.xrpl4j.crypto.core.keys.KeyPairService} instead.
*/
+ @Deprecated
Address deriveAddress(final PublicKey publicKey);
}
From 0aa0c9ae48d77ea8c659842436844bf0f15eab1c Mon Sep 17 00:00:00 2001
From: David Fuelling <323659+sappenin@users.noreply.github.com>
Date: Mon, 27 Jun 2022 12:53:35 -0600
Subject: [PATCH 09/12] Df/276 Enhance `AddressUtils` (#281)
* Update Javadoc
* Update and commit to AddressUtils
Signed-off-by: David Fuelling
---
.../xrpl4j/crypto/bc/BcAddressUtilsTest.java | 14 ++++++-
.../xrpl/xrpl4j/crypto/core/AddressUtils.java | 39 ++++++++++++++++++
.../xrpl/xrpl4j/keypairs/KeyPairService.java | 41 +++++++++++++++----
3 files changed, 85 insertions(+), 9 deletions(-)
diff --git a/xrpl4j-crypto-parent/xrpl4j-crypto-bouncycastle/src/test/java/org/xrpl/xrpl4j/crypto/bc/BcAddressUtilsTest.java b/xrpl4j-crypto-parent/xrpl4j-crypto-bouncycastle/src/test/java/org/xrpl/xrpl4j/crypto/bc/BcAddressUtilsTest.java
index c06964a1c..11193558e 100644
--- a/xrpl4j-crypto-parent/xrpl4j-crypto-bouncycastle/src/test/java/org/xrpl/xrpl4j/crypto/bc/BcAddressUtilsTest.java
+++ b/xrpl4j-crypto-parent/xrpl4j-crypto-bouncycastle/src/test/java/org/xrpl/xrpl4j/crypto/bc/BcAddressUtilsTest.java
@@ -5,6 +5,7 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.xrpl.xrpl4j.crypto.bc.wallet.BcWalletFactory;
+import org.xrpl.xrpl4j.crypto.core.AddressUtils;
import org.xrpl.xrpl4j.crypto.core.keys.Passphrase;
import org.xrpl.xrpl4j.crypto.core.keys.PublicKey;
import org.xrpl.xrpl4j.crypto.core.keys.Seed;
@@ -16,16 +17,25 @@
class BcAddressUtilsTest {
@Test
- public void deriveAddressWithNull() {
+ void deriveAddressWithNull() {
Assertions.assertThrows(NullPointerException.class, () -> BcAddressUtils.getInstance().deriveAddress(null));
}
@Test
- public void deriveAddress() {
+ void deriveAddress() {
PublicKey publicKey = BcWalletFactory.getInstance()
.fromSeed(Seed.ed25519SeedFromPassphrase(Passphrase.of("hello"))).publicKey();
Address address = BcAddressUtils.getInstance().deriveAddress(publicKey);
assertThat(address.value()).isEqualTo("rwGWYtRR6jJJJq7FKQg74YwtkiPyUqJ466");
}
+ @Test
+ void testAddressConstants() {
+ assertThat(AddressUtils.ACCOUNT_ZERO.value()).isEqualTo("rrrrrrrrrrrrrrrrrrrrrhoLvTp");
+ assertThat(AddressUtils.ACCOUNT_ONE.value()).isEqualTo("rrrrrrrrrrrrrrrrrrrrBZbvji");
+ assertThat(AddressUtils.GENESIS_ACCOUNT.value()).isEqualTo("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
+ assertThat(AddressUtils.NAME_RESERVATION_BLACKHOLD.value()).isEqualTo("rrrrrrrrrrrrrrrrrNAMEtxvNvQ");
+ assertThat(AddressUtils.NAN_ADDRESS.value()).isEqualTo("rrrrrrrrrrrrrrrrrrrn5RM1rHd");
+ }
+
}
\ No newline at end of file
diff --git a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/AddressUtils.java b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/AddressUtils.java
index 9353c14c2..48afba0ba 100644
--- a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/AddressUtils.java
+++ b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/AddressUtils.java
@@ -8,6 +8,45 @@
*/
public interface AddressUtils {
+ /**
+ * An address that is the XRP Ledger's base58 encoding of the value 0. In peer-to-peer communications, rippled uses
+ * this address as the issuer for XRP. This is a Black hole account.
+ *
+ * @see "https://xrpl.org/accounts.html#special-addresses"
+ */
+ Address ACCOUNT_ZERO = Address.of("rrrrrrrrrrrrrrrrrrrrrhoLvTp");
+
+ /**
+ * An address that is the XRP Ledger's base58 encoding of the value 1. In the ledger, RippleState entries use this
+ * address as a placeholder for the issuer of a trust line balance. This is a Black hole account.
+ *
+ * @see "https://xrpl.org/accounts.html#special-addresses"
+ */
+ Address ACCOUNT_ONE = Address.of("rrrrrrrrrrrrrrrrrrrrBZbvji");
+
+ /**
+ * When rippled starts a new genesis ledger from scratch (for example, in stand-alone mode), this account holds all
+ * the XRP. This address is generated from the seed value masterpassphrase which is hard-coded.
+ *
+ * @see "https://xrpl.org/accounts.html#special-addresses"
+ */
+ Address GENESIS_ACCOUNT = Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
+
+ /**
+ * In the past, Ripple asked users to send XRP to this account to reserve Ripple Names. This is a Black hole account.
+ *
+ * @see "https://xrpl.org/accounts.html#special-addresses"
+ */
+ Address NAME_RESERVATION_BLACKHOLD = Address.of("rrrrrrrrrrrrrrrrrNAMEtxvNvQ");
+
+ /**
+ * Previous versions of ripple-lib generated this address when encoding the value NaN using the XRP Ledger's base58
+ * string encoding format. This is a Black hole account.
+ *
+ * @see "https://xrpl.org/accounts.html#special-addresses"
+ */
+ Address NAN_ADDRESS = Address.of("rrrrrrrrrrrrrrrrrrrn5RM1rHd");
+
/**
* Derive an XRPL address from a public key.
*
diff --git a/xrpl4j-keypairs/src/main/java/org/xrpl/xrpl4j/keypairs/KeyPairService.java b/xrpl4j-keypairs/src/main/java/org/xrpl/xrpl4j/keypairs/KeyPairService.java
index 116406322..e67e216ad 100644
--- a/xrpl4j-keypairs/src/main/java/org/xrpl/xrpl4j/keypairs/KeyPairService.java
+++ b/xrpl4j-keypairs/src/main/java/org/xrpl/xrpl4j/keypairs/KeyPairService.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.
@@ -24,8 +24,8 @@
import org.xrpl.xrpl4j.model.transactions.Address;
/**
- * Interface of a service that can perform the crypto operations necessary to create a wallet,
- * sign and verify XRPL transactions, and derive XRPL addresses.
+ * Interface of a service that can perform the crypto operations necessary to create a wallet, sign and verify XRPL
+ * transactions, and derive XRPL addresses.
*
* @deprecated This class will go away in a future version. Prefer xrpl4j-crypto variants instead.
*/
@@ -36,7 +36,10 @@ public interface KeyPairService {
* Generate a random 16 byte seed to be used to derive a private key.
*
* @return A {@link String} containing a randomly generated Base58Check encoded seed value.
+ *
+ * @deprecated This class will go away in a future version. Prefer xrpl4j-crypto variants instead.
*/
+ @Deprecated
String generateSeed();
/**
@@ -45,7 +48,10 @@ public interface KeyPairService {
* @param entropy An {@link UnsignedByteArray} containing the bytes of entropy to encode into a seed.
*
* @return A {@link String} containing the Base58Check encoded seed value.
+ *
+ * @deprecated This class will go away in a future version. Prefer xrpl4j-crypto variants instead.
*/
+ @Deprecated
String generateSeed(UnsignedByteArray entropy);
/**
@@ -54,7 +60,10 @@ public interface KeyPairService {
* @param seed A Base58Check encoded {@link String} containing the seed.
*
* @return The {@link KeyPair} derived from the seed.
+ *
+ * @deprecated This class will go away in a future version. Prefer xrpl4j-crypto variants instead.
*/
+ @Deprecated
KeyPair deriveKeyPair(String seed);
/**
@@ -64,7 +73,10 @@ public interface KeyPairService {
* @param privateKey The hexadecimal encoded private key used to sign the transaction.
*
* @return The signed message, in hexadecimal form.
+ *
+ * @deprecated This class will go away in a future version. Prefer xrpl4j-crypto variants instead.
*/
+ @Deprecated
String sign(UnsignedByteArray message, String privateKey);
/**
@@ -74,7 +86,8 @@ public interface KeyPairService {
* @param privateKey The hexadecimal encoded private key used to sign the transaction.
*
* @return The signed message, in hexadecimal form.
- * @deprecated Consider using TransactionSigner instead.
+ *
+ * @deprecated Consider using TransactionSigner instead from xrpl4j-crypto.
*/
@Deprecated
String sign(String message, String privateKey);
@@ -84,10 +97,14 @@ public interface KeyPairService {
*
* @param message The arbitrary message that was signed with a private key.
* @param signature The hexadecimal encoded {@link String} containing the signature to verify.
- * @param publicKey The hexadecimal encoded public key derived from the private key that was used to sign the message.
+ * @param publicKey The hexadecimal encoded public key derived from the private key that was used to sign the
+ * message.
*
* @return true if the signature is valid, false if not.
+ *
+ * @deprecated Consider using TransactionVerifier instead from xrpl4j-crypto.
*/
+ @Deprecated
boolean verify(UnsignedByteArray message, String signature, String publicKey);
/**
@@ -95,10 +112,14 @@ public interface KeyPairService {
*
* @param message The hexadecimal encoded arbitrary message that was signed with a private key.
* @param signature The hexadecimal encoded {@link String} containing the signature to verify.
- * @param publicKey The hexadecimal encoded public key derived from the private key that was used to sign the message.
+ * @param publicKey The hexadecimal encoded public key derived from the private key that was used to sign the
+ * message.
*
* @return true if the signature is valid, false if not.
+ *
+ * @deprecated Consider using TransactionVerifier instead from xrpl4j-crypto.
*/
+ @Deprecated
boolean verify(String message, String signature, String publicKey);
/**
@@ -107,7 +128,10 @@ public interface KeyPairService {
* @param publicKey The hexadecimal encoded public key of the account.
*
* @return A Base58Check encoded XRPL address in Classic Address form.
+ *
+ * @deprecated Consider using AddressUtils instead.
*/
+ @Deprecated
Address deriveAddress(String publicKey);
/**
@@ -116,7 +140,10 @@ public interface KeyPairService {
* @param publicKey The public key of the account.
*
* @return A Base58Check encoded XRPL address in Classic Address form.
+ *
+ * @deprecated Consider using AddressUtils instead.
*/
+ @Deprecated
Address deriveAddress(UnsignedByteArray publicKey);
}
From 698c030a7438d4b51d548fd8beffb932dfb327b9 Mon Sep 17 00:00:00 2001
From: Mukul Jangid <49061120+mukulljangid@users.noreply.github.com>
Date: Mon, 18 Jul 2022 12:36:52 -0400
Subject: [PATCH 10/12] Mj/use feeutils v3 (#280)
* use FeeUtils for v3 ITs
Co-authored-by: David Fuelling
---
.../org/xrpl/xrpl4j/tests/AbstractIT.java | 36 +-
.../org/xrpl/xrpl4j/tests/AccountSetIT.java | 29 +-
.../java/org/xrpl/xrpl4j/tests/CheckIT.java | 13 +-
.../xrpl/xrpl4j/tests/DepositPreAuthIT.java | 7 +-
.../java/org/xrpl/xrpl4j/tests/IsFinalIT.java | 3 +-
.../xrpl/xrpl4j/tests/IssuedCurrencyIT.java | 7 +-
.../java/org/xrpl/xrpl4j/tests/OfferIT.java | 11 +-
.../xrpl/xrpl4j/tests/PaymentChannelIT.java | 15 +-
.../xrpl/xrpl4j/tests/SetRegularKeyIT.java | 11 +-
.../xrpl/xrpl4j/tests/SignerListSetIT.java | 18 +-
.../xrpl4j/tests/SubmitMultisignedIT.java | 16 +-
.../xrpl/xrpl4j/tests/SubmitPaymentIT.java | 5 +-
.../java/org/xrpl/xrpl4j/tests/TicketIT.java | 5 +-
.../xrpl4j/tests/TransactionWithMemoIT.java | 5 +-
.../xrpl/xrpl4j/tests/v3/AccountSetIT.java | 9 +-
.../org/xrpl/xrpl4j/tests/v3/CheckIT.java | 13 +-
.../xrpl4j/tests/v3/DepositPreAuthIT.java | 12 +-
.../tests/v3/FreezeIssuedCurrencyIT.java | 45 +-
.../xrpl4j/tests/v3/IssuedCurrencyIT.java | 46 +-
.../org/xrpl/xrpl4j/tests/v3/OfferIT.java | 13 +-
.../xrpl4j/tests/v3/PaymentChannelIT.java | 15 +-
.../xrpl/xrpl4j/tests/v3/SetRegularKeyIT.java | 11 +-
.../xrpl/xrpl4j/tests/v3/SignerListSetIT.java | 12 +-
.../xrpl/xrpl4j/tests/v3/SubmitPaymentIT.java | 5 +-
...ransactUsingDelegatedSignatureService.java | 14 +-
.../v3/TransactUsingSignatureService.java | 14 +-
.../AccountCurrenciesRequestParams.java | 16 +-
.../client/fees/ComputedNetworkFees.java | 91 +++
.../xrpl4j/model/client/fees/FeeResult.java | 16 +-
.../xrpl4j/model/client/fees/FeeUtils.java | 432 +++++++++++++
.../model/transactions/CurrencyAmount.java | 24 +-
.../model/transactions/Transaction.java | 7 +-
.../xrpl4j/model/transactions/Wrappers.java | 30 +-
.../model/client/fees/DecomposedFeesTest.java | 151 +++++
.../model/client/fees/FeeUtilsTest.java | 574 ++++++++++++++++++
.../client/fees/NetworkFeeResultTests.java | 78 +++
.../transactions/CurrencyAmountTest.java | 11 +-
.../model/transactions/EscrowFinishTest.java | 2 +-
38 files changed, 1621 insertions(+), 201 deletions(-)
create mode 100644 xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/ComputedNetworkFees.java
create mode 100644 xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeUtils.java
create mode 100644 xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/DecomposedFeesTest.java
create mode 100644 xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/FeeUtilsTest.java
create mode 100644 xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/NetworkFeeResultTests.java
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 5c4c53f1b..368834d06 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
@@ -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.
@@ -41,6 +41,9 @@
import org.xrpl.xrpl4j.model.client.accounts.AccountObjectsResult;
import org.xrpl.xrpl4j.model.client.accounts.TrustLine;
import org.xrpl.xrpl4j.model.client.common.LedgerSpecifier;
+import org.xrpl.xrpl4j.model.client.fees.ComputedNetworkFees;
+import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.ledger.LedgerRequestParams;
import org.xrpl.xrpl4j.model.client.ledger.LedgerResult;
import org.xrpl.xrpl4j.model.client.path.RipplePathFindRequestParams;
@@ -63,6 +66,7 @@
import org.xrpl.xrpl4j.wallet.Wallet;
import org.xrpl.xrpl4j.wallet.WalletFactory;
+import java.math.BigDecimal;
import java.time.Instant;
import java.util.List;
import java.util.Objects;
@@ -262,8 +266,8 @@ protected Instant xrpTimestampToInstant(UnsignedLong xrpTimeStamp) {
}
/**
- * Create a trustline between the given issuer and counterparty accounts for the given currency code and
- * with the given limit.
+ * Create a trustline between the given issuer and counterparty accounts for the given currency code and with the
+ * given limit.
*
* @param currency The currency code of the trustline to create.
* @param value The trustline limit of the trustline to create.
@@ -272,6 +276,7 @@ protected Instant xrpTimestampToInstant(UnsignedLong xrpTimeStamp) {
* @param fee The current network fee, as an {@link XrpCurrencyAmount}.
*
* @return The {@link TrustLine} that gets created.
+ *
* @throws JsonRpcClientErrorException If anything goes wrong while communicating with rippled.
*/
public TrustLine createTrustLine(
@@ -367,4 +372,27 @@ public void sendIssuedCurrency(
);
}
+
+ /**
+ * Send issued currency funds from an issuer to a counterparty.
+ *
+ * @param feeResult The {@link FeeResult} which has information from the api call to the network.
+ *
+ * @return The {@link ComputedNetworkFees} object woth 3 levels of fees.
+ *
+ * @throws JsonRpcClientErrorException If anything goes wrong while communicating with rippled.
+ */
+ protected XrpCurrencyAmount getComputedNetworkFee(FeeResult feeResult) {
+ ComputedNetworkFees networkFeeResult = FeeUtils.computeNetworkFees(feeResult);
+ final FeeUtils.DecomposedFees decomposedFees = FeeUtils.DecomposedFees.builder(feeResult);
+ final BigDecimal queuePercentage = decomposedFees.queuePercentage();
+
+ if (FeeUtils.queueIsEmpty(queuePercentage)) {
+ return networkFeeResult.feeLow();
+ } else if (FeeUtils.queueIsNotEmptyAndNotFull(queuePercentage)) {
+ return networkFeeResult.feeMedium();
+ } else {
+ return networkFeeResult.feeHigh();
+ }
+ }
}
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AccountSetIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AccountSetIT.java
index 8b8982c06..ec72e4c05 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AccountSetIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AccountSetIT.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.
@@ -27,6 +27,7 @@
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.flags.Flags;
import org.xrpl.xrpl4j.model.flags.Flags.AccountRootFlags;
@@ -61,19 +62,19 @@ public void enableAllAndDisableOne() throws JsonRpcClientErrorException {
// Set asfAccountTxnID (no corresponding ledger flag)
FeeResult feeResult = xrplClient.fee();
AccountSet accountSet = AccountSet.builder()
- .account(wallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
- .sequence(accountInfo.accountData().sequence())
- .setFlag(AccountSetFlag.ACCOUNT_TXN_ID)
- .signingPublicKey(wallet.publicKey())
- .build();
+ .account(wallet.classicAddress())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
+ .sequence(accountInfo.accountData().sequence())
+ .setFlag(AccountSetFlag.ACCOUNT_TXN_ID)
+ .signingPublicKey(wallet.publicKey())
+ .build();
SubmitResult response = xrplClient.submit(wallet, accountSet);
assertThat(response.result()).isEqualTo(TransactionResultCodes.TES_SUCCESS);
assertThat(response.transactionResult().transaction().hash()).isNotEmpty().get()
- .isEqualTo(response.transactionResult().hash());
+ .isEqualTo(response.transactionResult().hash());
logger.info(
- "AccountSet transaction successful: https://testnet.xrpl.org/transactions/" + response.transactionResult().hash()
+ "AccountSet transaction successful: https://testnet.xrpl.org/transactions/" + response.transactionResult().hash()
);
///////////////////////
@@ -103,7 +104,7 @@ public void enableAllAndDisableOne() throws JsonRpcClientErrorException {
).accountData().flags();
assertThat(flags1.getValue() - flags2.getValue())
- .isEqualTo(AccountRootFlags.GLOBAL_FREEZE.getValue());
+ .isEqualTo(AccountRootFlags.GLOBAL_FREEZE.getValue());
}
@Test
@@ -123,7 +124,7 @@ public void disableAndEnableAllFlags() throws JsonRpcClientErrorException {
FeeResult feeResult = xrplClient.fee();
AccountSet accountSet = AccountSet.builder()
.account(wallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.setFlag(AccountSetFlag.ACCOUNT_TXN_ID)
.signingPublicKey(wallet.publicKey())
@@ -292,7 +293,7 @@ private void assertSetFlag(
FeeResult feeResult = xrplClient.fee();
AccountSet accountSet = AccountSet.builder()
.account(wallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.setFlag(accountSetFlag)
.signingPublicKey(wallet.publicKey())
@@ -329,7 +330,7 @@ private void assertClearFlag(
FeeResult feeResult = xrplClient.fee();
AccountSet accountSet = AccountSet.builder()
.account(wallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.clearFlag(accountSetFlag)
.signingPublicKey(wallet.publicKey())
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/CheckIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/CheckIT.java
index 56f73f385..3bd556d09 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/CheckIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/CheckIT.java
@@ -28,6 +28,7 @@
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.ledger.CheckObject;
import org.xrpl.xrpl4j.model.ledger.LedgerObject;
@@ -61,7 +62,7 @@ public void createXrpCheckAndCash() throws JsonRpcClientErrorException {
Hash256 invoiceId = Hash256.of(Hashing.sha256().hashBytes("Check this out.".getBytes()).toString());
CheckCreate checkCreate = CheckCreate.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfoResult.accountData().sequence())
.destination(destinationWallet.classicAddress())
.sendMax(XrpCurrencyAmount.ofDrops(12345))
@@ -99,7 +100,7 @@ public void createXrpCheckAndCash() throws JsonRpcClientErrorException {
.account(destinationWallet.classicAddress())
.amount(checkObject.sendMax())
.sequence(destinationAccountInfo.accountData().sequence())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.checkId(checkObject.index())
.signingPublicKey(destinationWallet.publicKey())
.build();
@@ -150,7 +151,7 @@ public void createCheckAndSourceCancels() throws JsonRpcClientErrorException {
Hash256 invoiceId = Hash256.of(Hashing.sha256().hashBytes("Check this out.".getBytes()).toString());
CheckCreate checkCreate = CheckCreate.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfoResult.accountData().sequence())
.destination(destinationWallet.classicAddress())
.sendMax(XrpCurrencyAmount.ofDrops(12345))
@@ -184,7 +185,7 @@ public void createCheckAndSourceCancels() throws JsonRpcClientErrorException {
CheckCancel checkCancel = CheckCancel.builder()
.account(sourceWallet.classicAddress())
.sequence(accountInfoResult.accountData().sequence().plus(UnsignedInteger.ONE))
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.checkId(checkObject.index())
.signingPublicKey(sourceWallet.publicKey())
.build();
@@ -224,7 +225,7 @@ public void createCheckAndDestinationCancels() throws JsonRpcClientErrorExceptio
Hash256 invoiceId = Hash256.of(Hashing.sha256().hashBytes("Check this out.".getBytes()).toString());
CheckCreate checkCreate = CheckCreate.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfoResult.accountData().sequence())
.destination(destinationWallet.classicAddress())
.sendMax(XrpCurrencyAmount.ofDrops(12345))
@@ -261,7 +262,7 @@ public void createCheckAndDestinationCancels() throws JsonRpcClientErrorExceptio
CheckCancel checkCancel = CheckCancel.builder()
.account(destinationWallet.classicAddress())
.sequence(destinationAccountInfo.accountData().sequence())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.checkId(checkObject.index())
.signingPublicKey(destinationWallet.publicKey())
.build();
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/DepositPreAuthIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/DepositPreAuthIT.java
index 7497bb05e..4ff074ab2 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/DepositPreAuthIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/DepositPreAuthIT.java
@@ -29,6 +29,7 @@
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.path.DepositAuthorizedRequestParams;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.client.transactions.TransactionResult;
@@ -59,7 +60,7 @@ public void preauthorizeAccountAndReceivePayment() throws JsonRpcClientErrorExce
// Give Preauthorization for the sender to send a funds to the receiver
DepositPreAuth depositPreAuth = DepositPreAuth.builder()
.account(receiverWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(receiverAccountInfo.accountData().sequence())
.signingPublicKey(receiverWallet.publicKey())
.authorize(senderWallet.classicAddress())
@@ -100,7 +101,7 @@ public void preauthorizeAccountAndReceivePayment() throws JsonRpcClientErrorExce
);
Payment payment = Payment.builder()
.account(senderWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.signingPublicKey(senderWallet.publicKey())
.amount(XrpCurrencyAmount.ofDrops(12345))
@@ -164,7 +165,7 @@ public void accountUnableToReceivePaymentsWithoutPreauthorization() throws JsonR
);
Payment payment = Payment.builder()
.account(senderWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.signingPublicKey(senderWallet.publicKey())
.amount(XrpCurrencyAmount.ofDrops(12345))
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/IsFinalIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/IsFinalIT.java
index c22b746e1..2e385d199 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/IsFinalIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/IsFinalIT.java
@@ -12,6 +12,7 @@
import org.xrpl.xrpl4j.model.client.common.LedgerIndex;
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.LedgerRequestParams;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.transactions.ImmutablePayment;
@@ -52,7 +53,7 @@ void setup() throws JsonRpcClientErrorException {
Wallet destinationWallet = createRandomAccount();
payment = Payment.builder()
.account(wallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.classicAddress())
.amount(XrpCurrencyAmount.ofDrops(10))
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/IssuedCurrencyIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/IssuedCurrencyIT.java
index 805a28faa..3aaecb74c 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/IssuedCurrencyIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/IssuedCurrencyIT.java
@@ -32,6 +32,7 @@
import org.xrpl.xrpl4j.model.client.accounts.TrustLine;
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.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.transactions.AccountSet;
import org.xrpl.xrpl4j.model.transactions.IssuedCurrencyAmount;
@@ -163,7 +164,7 @@ public void sendSimpleRipplingIssuedCurrencyPayment() throws JsonRpcClientErrorE
AccountInfoResult aliceAccountInfo = getValidatedAccountInfo(aliceWallet.classicAddress());
Payment aliceToBobPayment = Payment.builder()
.account(aliceWallet.classicAddress())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(aliceAccountInfo.accountData().sequence())
.destination(bobWallet.classicAddress())
.amount(IssuedCurrencyAmount.builder()
@@ -307,7 +308,7 @@ public void sendMultiHopSameCurrencyPayment() throws JsonRpcClientErrorException
AccountInfoResult charlieAccountInfo = getValidatedAccountInfo(charlieWallet.classicAddress());
Payment charlieToDanielPayment = Payment.builder()
.account(charlieWallet.classicAddress())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(charlieAccountInfo.accountData().sequence())
.destination(danielWallet.classicAddress())
.amount(IssuedCurrencyAmount.builder()
@@ -371,7 +372,7 @@ public void setDefaultRipple(Wallet issuerWallet, FeeResult feeResult) throws Js
AccountSet setDefaultRipple = AccountSet.builder()
.account(issuerWallet.classicAddress())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(issuerAccountInfo.accountData().sequence())
.signingPublicKey(issuerWallet.publicKey())
.setFlag(AccountSet.AccountSetFlag.DEFAULT_RIPPLE)
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/OfferIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/OfferIT.java
index 8367a0b6d..a25d49911 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/OfferIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/OfferIT.java
@@ -30,6 +30,7 @@
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.flags.Flags;
import org.xrpl.xrpl4j.model.ledger.OfferObject;
@@ -77,7 +78,7 @@ public void ensureUsdIssued() throws JsonRpcClientErrorException {
UnsignedInteger sequence = accountInfoResult.accountData().sequence();
OfferCreate offerCreate = OfferCreate.builder()
.account(issuerWallet.classicAddress())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.signingPublicKey(issuerWallet.publicKey())
.takerGets(IssuedCurrencyAmount.builder()
@@ -126,7 +127,7 @@ public void createOpenOfferAndCancel() throws JsonRpcClientErrorException {
UnsignedInteger sequence = accountInfoResult.accountData().sequence();
OfferCreate offerCreate = OfferCreate.builder()
.account(purchaser.classicAddress())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.signingPublicKey(purchaser.publicKey())
.takerPays(IssuedCurrencyAmount.builder()
@@ -181,7 +182,7 @@ private void cancelOffer(
OfferCancel offerCancel = OfferCancel.builder()
.account(purchaser.classicAddress())
- .fee(xrplClient.fee().drops().minimumFee())
+ .fee(getComputedNetworkFee(xrplClient.fee()))
.sequence(nextSequence)
.offerSequence(offerSequence)
.signingPublicKey(purchaser.publicKey())
@@ -213,7 +214,7 @@ public void createUnmatchedKillOrFill() throws JsonRpcClientErrorException {
UnsignedInteger sequence = accountInfoResult.accountData().sequence();
OfferCreate offerCreate = OfferCreate.builder()
.account(purchaser.classicAddress())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.signingPublicKey(purchaser.publicKey())
.takerPays(IssuedCurrencyAmount.builder()
@@ -278,7 +279,7 @@ public void createFullyMatchedOffer() throws JsonRpcClientErrorException {
OfferCreate offerCreate = OfferCreate.builder()
.account(purchaser.classicAddress())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.signingPublicKey(purchaser.publicKey())
.takerPays(requestCurrencyAmount)
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/PaymentChannelIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/PaymentChannelIT.java
index 6fee8ed53..c3b7a4ae9 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/PaymentChannelIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/PaymentChannelIT.java
@@ -40,6 +40,7 @@
import org.xrpl.xrpl4j.model.client.channels.UnsignedClaim;
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.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory;
import org.xrpl.xrpl4j.model.ledger.PayChannelObject;
@@ -76,7 +77,7 @@ public void createPaymentChannel() throws JsonRpcClientErrorException {
// the source and destination accounts
PaymentChannelCreate createPaymentChannel = PaymentChannelCreate.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(10000))
.destination(destinationWallet.classicAddress())
@@ -158,7 +159,7 @@ void createAndClaimPaymentChannel() throws JsonRpcClientErrorException, JsonProc
// the source and destination accounts
PaymentChannelCreate createPaymentChannel = PaymentChannelCreate.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(10000000))
.destination(destinationWallet.classicAddress())
@@ -233,7 +234,7 @@ void createAndClaimPaymentChannel() throws JsonRpcClientErrorException, JsonProc
// Destination account submits the signed claim to the ledger to get their XRP
PaymentChannelClaim signedClaim = PaymentChannelClaim.builder()
.account(destinationWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(destinationAccountInfo.accountData().sequence())
.channel(paymentChannel.channelId())
.balance(paymentChannel.balance().plus(unsignedClaim.amount()))
@@ -280,7 +281,7 @@ void createAddFundsAndSetExpirationToPaymentChannel() throws JsonRpcClientErrorE
// the source and destination accounts
PaymentChannelCreate createPaymentChannel = PaymentChannelCreate.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(10000000))
.destination(destinationWallet.classicAddress())
@@ -320,7 +321,7 @@ void createAddFundsAndSetExpirationToPaymentChannel() throws JsonRpcClientErrorE
PaymentChannelFund addFunds = PaymentChannelFund.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence().plus(UnsignedInteger.ONE))
.signingPublicKey(sourceWallet.publicKey())
.channel(paymentChannel.channelId())
@@ -358,7 +359,7 @@ void createAddFundsAndSetExpirationToPaymentChannel() throws JsonRpcClientErrorE
PaymentChannelFund setExpiry = PaymentChannelFund.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence().plus(UnsignedInteger.valueOf(2)))
.signingPublicKey(sourceWallet.publicKey())
.channel(paymentChannel.channelId())
@@ -407,7 +408,7 @@ void testCurrentAccountChannels() throws JsonRpcClientErrorException {
// the source and destination accounts
PaymentChannelCreate createPaymentChannel = PaymentChannelCreate.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(10000))
.destination(destinationWallet.classicAddress())
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SetRegularKeyIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SetRegularKeyIT.java
index 6c89f907f..25a1fa6a2 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SetRegularKeyIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SetRegularKeyIT.java
@@ -27,6 +27,7 @@
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.transactions.AccountSet;
import org.xrpl.xrpl4j.model.transactions.SetRegularKey;
@@ -55,7 +56,7 @@ void setRegularKeyOnAccount() throws JsonRpcClientErrorException {
FeeResult feeResult = xrplClient.fee();
SetRegularKey setRegularKey = SetRegularKey.builder()
.account(wallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.regularKey(newWallet.classicAddress())
.signingPublicKey(wallet.publicKey())
@@ -77,7 +78,7 @@ void setRegularKeyOnAccount() throws JsonRpcClientErrorException {
() -> {
AccountSet accountSet = AccountSet.builder()
.account(wallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence().plus(UnsignedInteger.ONE))
.signingPublicKey(newWallet.publicKey())
.build();
@@ -112,7 +113,7 @@ void removeRegularKeyFromAccount() throws JsonRpcClientErrorException {
FeeResult feeResult = xrplClient.fee();
SetRegularKey setRegularKey = SetRegularKey.builder()
.account(wallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.regularKey(newWallet.classicAddress())
.signingPublicKey(wallet.publicKey())
@@ -134,7 +135,7 @@ void removeRegularKeyFromAccount() throws JsonRpcClientErrorException {
() -> {
AccountSet accountSet = AccountSet.builder()
.account(wallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence().plus(UnsignedInteger.ONE))
.signingPublicKey(newWallet.publicKey())
.build();
@@ -150,7 +151,7 @@ void removeRegularKeyFromAccount() throws JsonRpcClientErrorException {
SetRegularKey removeRegularKey = SetRegularKey.builder()
.account(wallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence().plus(UnsignedInteger.valueOf(2)))
.signingPublicKey(wallet.publicKey())
.build();
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SignerListSetIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SignerListSetIT.java
index 8b9727b7a..f23971d68 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SignerListSetIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SignerListSetIT.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.
@@ -33,6 +33,7 @@
import org.xrpl.xrpl4j.keypairs.KeyPairService;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitMultiSignedResult;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory;
@@ -42,7 +43,6 @@
import org.xrpl.xrpl4j.model.transactions.Signer;
import org.xrpl.xrpl4j.model.transactions.SignerListSet;
import org.xrpl.xrpl4j.model.transactions.SignerWrapper;
-import org.xrpl.xrpl4j.model.transactions.Transaction;
import org.xrpl.xrpl4j.model.transactions.TransactionResultCodes;
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
import org.xrpl.xrpl4j.wallet.Wallet;
@@ -85,7 +85,7 @@ void addSignersToSignerListAndSendPayment() throws JsonRpcClientErrorException {
FeeResult feeResult = xrplClient.fee();
SignerListSet signerListSet = SignerListSet.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sourceAccountInfo.accountData().sequence())
.signerQuorum(UnsignedInteger.valueOf(2))
.addSignerEntries(
@@ -110,7 +110,7 @@ void addSignersToSignerListAndSendPayment() throws JsonRpcClientErrorException {
SubmitResult signerListSetResult = xrplClient.submit(sourceWallet, signerListSet);
assertThat(signerListSetResult.result()).isEqualTo(TransactionResultCodes.TES_SUCCESS);
assertThat(signerListSetResult.transactionResult().transaction().hash()).isNotEmpty().get()
- .isEqualTo(signerListSetResult.transactionResult().hash());
+ .isEqualTo(signerListSetResult.transactionResult().hash());
logger.info(
"SignerListSet transaction successful: https://testnet.xrpl.org/transactions/" +
signerListSetResult.transactionResult().hash()
@@ -138,10 +138,10 @@ void addSignersToSignerListAndSendPayment() throws JsonRpcClientErrorException {
Payment unsignedPayment = Payment.builder()
.account(sourceWallet.classicAddress())
.fee(
- Transaction.computeMultiSigFee(
- feeResult.drops().openLedgerFee(),
+ FeeUtils.computeMultisigNetworkFees(
+ feeResult,
sourceAccountInfoAfterSignerListSet.accountData().signerLists().get(0)
- )
+ ).recommendedFee()
)
.sequence(sourceAccountInfoAfterSignerListSet.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(12345))
@@ -214,7 +214,7 @@ void addSignersToSignerListThenDeleteSignerList() throws JsonRpcClientErrorExcep
FeeResult feeResult = xrplClient.fee();
SignerListSet signerListSet = SignerListSet.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sourceAccountInfo.accountData().sequence())
.signerQuorum(UnsignedInteger.valueOf(2))
.addSignerEntries(
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitMultisignedIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitMultisignedIT.java
index e3a05f496..39110161d 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitMultisignedIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitMultisignedIT.java
@@ -15,6 +15,7 @@
import org.xrpl.xrpl4j.keypairs.KeyPairService;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SignedTransaction;
import org.xrpl.xrpl4j.model.client.transactions.SubmitMultiSignedResult;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
@@ -26,7 +27,6 @@
import org.xrpl.xrpl4j.model.transactions.Signer;
import org.xrpl.xrpl4j.model.transactions.SignerListSet;
import org.xrpl.xrpl4j.model.transactions.SignerWrapper;
-import org.xrpl.xrpl4j.model.transactions.Transaction;
import org.xrpl.xrpl4j.model.transactions.TransactionResultCodes;
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
import org.xrpl.xrpl4j.wallet.Wallet;
@@ -75,7 +75,7 @@ public void setUp() throws JsonRpcClientErrorException {
feeResult = xrplClient.fee();
SignerListSet signerListSet = SignerListSet.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sourceAccountInfo.accountData().sequence())
.signerQuorum(UnsignedInteger.valueOf(2))
.addSignerEntries(
@@ -132,10 +132,10 @@ public void submitMultisignedAndVerifyHash() throws JsonRpcClientErrorException,
Payment unsignedPayment = Payment.builder()
.account(sourceWallet.classicAddress())
.fee(
- Transaction.computeMultiSigFee(
- feeResult.drops().openLedgerFee(),
+ FeeUtils.computeMultisigNetworkFees(
+ feeResult,
sourceAccountInfoAfterSignerListSet.accountData().signerLists().get(0)
- )
+ ).recommendedFee()
)
.sequence(sourceAccountInfoAfterSignerListSet.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(12345))
@@ -201,10 +201,10 @@ public void submitMultisignedWithSignersInDescOrderAndVerifyHash() throws
Payment unsignedPayment = Payment.builder()
.account(sourceWallet.classicAddress())
.fee(
- Transaction.computeMultiSigFee(
- feeResult.drops().openLedgerFee(),
+ FeeUtils.computeMultisigNetworkFees(
+ feeResult,
sourceAccountInfoAfterSignerListSet.accountData().signerLists().get(0)
- )
+ ).recommendedFee()
)
.sequence(sourceAccountInfoAfterSignerListSet.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(12345))
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitPaymentIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitPaymentIT.java
index ad712fe9d..66fc80871 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitPaymentIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/SubmitPaymentIT.java
@@ -27,6 +27,7 @@
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
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.LedgerRequestParams;
import org.xrpl.xrpl4j.model.client.ledger.LedgerResult;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
@@ -50,7 +51,7 @@ public void sendPayment() throws JsonRpcClientErrorException {
XrpCurrencyAmount amount = XrpCurrencyAmount.ofDrops(12345);
Payment payment = Payment.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.classicAddress())
.amount(amount)
@@ -93,7 +94,7 @@ public void sendPaymentFromSecp256k1Wallet() throws JsonRpcClientErrorException
Payment payment = Payment.builder()
.account(senderWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.classicAddress())
.amount(XrpCurrencyAmount.ofDrops(12345))
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TicketIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TicketIT.java
index f4a89fa18..a31b4d7a3 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TicketIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TicketIT.java
@@ -27,6 +27,7 @@
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.ledger.TicketObject;
import org.xrpl.xrpl4j.model.transactions.AccountSet;
@@ -49,7 +50,7 @@ void createTicketAndUseSequenceNumber() throws JsonRpcClientErrorException {
TicketCreate ticketCreate = TicketCreate.builder()
.account(sourceWallet.classicAddress())
.sequence(accountInfo.accountData().sequence())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.ticketCount(UnsignedInteger.ONE)
.signingPublicKey(sourceWallet.publicKey())
.build();
@@ -71,7 +72,7 @@ void createTicketAndUseSequenceNumber() throws JsonRpcClientErrorException {
AccountSet accountSet = AccountSet.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.ticketSequence(tickets.get(0).ticketSequence())
.signingPublicKey(sourceWallet.publicKey())
.build();
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TransactionWithMemoIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TransactionWithMemoIT.java
index 1575c0615..261e1ba8a 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TransactionWithMemoIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/TransactionWithMemoIT.java
@@ -26,6 +26,7 @@
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.client.transactions.TransactionResult;
import org.xrpl.xrpl4j.model.transactions.Memo;
@@ -51,7 +52,7 @@ public void transactionWithMemoNibble() throws JsonRpcClientErrorException {
XrpCurrencyAmount amount = XrpCurrencyAmount.ofDrops(12345);
Payment payment = Payment.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.classicAddress())
.amount(amount)
@@ -96,7 +97,7 @@ public void transactionWithPlaintextMemo() throws JsonRpcClientErrorException {
XrpCurrencyAmount amount = XrpCurrencyAmount.ofDrops(12345);
Payment payment = Payment.builder()
.account(sourceWallet.classicAddress())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.classicAddress())
.amount(amount)
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/AccountSetIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/AccountSetIT.java
index 3232bab1a..bf5017998 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/AccountSetIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/AccountSetIT.java
@@ -10,6 +10,7 @@
import org.xrpl.xrpl4j.crypto.core.wallet.Wallet;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.flags.Flags.AccountRootFlags;
import org.xrpl.xrpl4j.model.transactions.AccountSet;
@@ -43,7 +44,7 @@ public void enableAllAndDisableOne() throws JsonRpcClientErrorException, JsonPro
FeeResult feeResult = xrplClient.fee();
AccountSet accountSet = AccountSet.builder()
.account(wallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.setFlag(AccountSetFlag.ACCOUNT_TXN_ID)
.signingPublicKey(wallet.publicKey().base16Value())
@@ -107,7 +108,7 @@ public void disableAndEnableAllFlags() throws JsonRpcClientErrorException, JsonP
FeeResult feeResult = xrplClient.fee();
AccountSet accountSet = AccountSet.builder()
.account(wallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.setFlag(AccountSetFlag.ACCOUNT_TXN_ID)
.signingPublicKey(wallet.publicKey().base16Value())
@@ -169,7 +170,7 @@ private void assertSetFlag(
FeeResult feeResult = xrplClient.fee();
AccountSet accountSet = AccountSet.builder()
.account(wallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.setFlag(accountSetFlag)
.signingPublicKey(wallet.publicKey().base16Value())
@@ -209,7 +210,7 @@ private void assertClearFlag(
FeeResult feeResult = xrplClient.fee();
AccountSet accountSet = AccountSet.builder()
.account(wallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.clearFlag(accountSetFlag)
.signingPublicKey(wallet.publicKey().base16Value())
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/CheckIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/CheckIT.java
index 1daf68769..97d36502b 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/CheckIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/CheckIT.java
@@ -11,6 +11,7 @@
import org.xrpl.xrpl4j.crypto.core.wallet.Wallet;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.ledger.CheckObject;
import org.xrpl.xrpl4j.model.ledger.LedgerObject;
@@ -46,7 +47,7 @@ public void createXrpCheckAndCash() throws JsonRpcClientErrorException, JsonProc
Hash256 invoiceId = Hash256.of(Hashing.sha256().hashBytes("Check this out.".getBytes()).toString());
CheckCreate checkCreate = CheckCreate.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfoResult.accountData().sequence())
.destination(destinationWallet.address())
.sendMax(XrpCurrencyAmount.ofDrops(12345))
@@ -86,7 +87,7 @@ public void createXrpCheckAndCash() throws JsonRpcClientErrorException, JsonProc
.account(destinationWallet.address())
.amount(checkObject.sendMax())
.sequence(destinationAccountInfo.accountData().sequence())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.checkId(checkObject.index())
.signingPublicKey(destinationWallet.publicKey().base16Value())
.build();
@@ -138,7 +139,7 @@ public void createCheckAndSourceCancels() throws JsonRpcClientErrorException, Js
Hash256 invoiceId = Hash256.of(Hashing.sha256().hashBytes("Check this out.".getBytes()).toString());
CheckCreate checkCreate = CheckCreate.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfoResult.accountData().sequence())
.destination(destinationWallet.address())
.sendMax(XrpCurrencyAmount.ofDrops(12345))
@@ -173,7 +174,7 @@ public void createCheckAndSourceCancels() throws JsonRpcClientErrorException, Js
CheckCancel checkCancel = CheckCancel.builder()
.account(sourceWallet.address())
.sequence(accountInfoResult.accountData().sequence().plus(UnsignedInteger.ONE))
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.checkId(checkObject.index())
.signingPublicKey(sourceWallet.publicKey().base16Value())
.build();
@@ -214,7 +215,7 @@ public void createCheckAndDestinationCancels() throws JsonRpcClientErrorExceptio
Hash256 invoiceId = Hash256.of(Hashing.sha256().hashBytes("Check this out.".getBytes()).toString());
CheckCreate checkCreate = CheckCreate.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfoResult.accountData().sequence())
.destination(destinationWallet.address())
.sendMax(XrpCurrencyAmount.ofDrops(12345))
@@ -253,7 +254,7 @@ public void createCheckAndDestinationCancels() throws JsonRpcClientErrorExceptio
CheckCancel checkCancel = CheckCancel.builder()
.account(destinationWallet.address())
.sequence(destinationAccountInfo.accountData().sequence())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.checkId(checkObject.index())
.signingPublicKey(destinationWallet.publicKey().base16Value())
.build();
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/DepositPreAuthIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/DepositPreAuthIT.java
index cdd0a64d0..1876a3edf 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/DepositPreAuthIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/DepositPreAuthIT.java
@@ -12,6 +12,7 @@
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.path.DepositAuthorizedRequestParams;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.client.transactions.TransactionResult;
@@ -37,13 +38,14 @@ public void preauthorizeAccountAndReceivePayment() throws JsonRpcClientErrorExce
/////////////////////////
// Enable Deposit Preauthorization on the receiver account
FeeResult feeResult = xrplClient.fee();
- AccountInfoResult receiverAccountInfo = enableDepositPreauth(receiverWallet, feeResult.drops().openLedgerFee());
+ AccountInfoResult receiverAccountInfo =
+ enableDepositPreauth(receiverWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee());
/////////////////////////
// Give Preauthorization for the sender to send a funds to the receiver
DepositPreAuth depositPreAuth = DepositPreAuth.builder()
.account(receiverWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(receiverAccountInfo.accountData().sequence())
.signingPublicKey(receiverWallet.publicKey().base16Value())
.authorize(senderWallet.address())
@@ -88,7 +90,7 @@ public void preauthorizeAccountAndReceivePayment() throws JsonRpcClientErrorExce
);
Payment payment = Payment.builder()
.account(senderWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.signingPublicKey(senderWallet.publicKey().base16Value())
.amount(XrpCurrencyAmount.ofDrops(12345))
@@ -135,7 +137,7 @@ public void accountUnableToReceivePaymentsWithoutPreauthorization()
/////////////////////////
// Enable Deposit Preauthorization on the receiver account
FeeResult feeResult = xrplClient.fee();
- enableDepositPreauth(receiverWallet, feeResult.drops().openLedgerFee());
+ enableDepositPreauth(receiverWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee());
/////////////////////////
// Validate that the receiver has not given authorization to anyone to send them Payments
@@ -154,7 +156,7 @@ public void accountUnableToReceivePaymentsWithoutPreauthorization()
);
Payment payment = Payment.builder()
.account(senderWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.signingPublicKey(senderWallet.publicKey().base16Value())
.amount(XrpCurrencyAmount.ofDrops(12345))
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/FreezeIssuedCurrencyIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/FreezeIssuedCurrencyIT.java
index 7a7bb05c8..02d5b6446 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/FreezeIssuedCurrencyIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/FreezeIssuedCurrencyIT.java
@@ -13,6 +13,7 @@
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.accounts.TrustLine;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.flags.Flags.TrustSetFlags;
import org.xrpl.xrpl4j.model.flags.Flags.TrustSetFlags.Builder;
@@ -67,7 +68,7 @@ public void issueAndFreezeFundsIndividual() throws JsonRpcClientErrorException,
TrustLine badActorTrustLine = this.createTrustLine(
issuerWallet,
badActorWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
assertThat(badActorTrustLine.freeze()).isFalse();
assertThat(badActorTrustLine.freezePeer()).isFalse();
@@ -79,7 +80,7 @@ public void issueAndFreezeFundsIndividual() throws JsonRpcClientErrorException,
TrustLine goodActorTrustLine = this.createTrustLine(
issuerWallet,
goodActorWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
assertThat(goodActorTrustLine.freeze()).isFalse();
assertThat(goodActorTrustLine.freezePeer()).isFalse();
@@ -92,7 +93,7 @@ public void issueAndFreezeFundsIndividual() throws JsonRpcClientErrorException,
// Send funds from issuer to the badActor.
sendFunds(
- TEN_THOUSAND, issuerWallet, badActorWallet, feeResult.drops().minimumFee()
+ TEN_THOUSAND, issuerWallet, badActorWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
@@ -105,7 +106,7 @@ public void issueAndFreezeFundsIndividual() throws JsonRpcClientErrorException,
// Send funds from badActor to the goodActor.
sendFunds(
- FIVE_THOUSAND, badActorWallet, goodActorWallet, feeResult.drops().minimumFee()
+ FIVE_THOUSAND, badActorWallet, goodActorWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
@@ -120,7 +121,7 @@ public void issueAndFreezeFundsIndividual() throws JsonRpcClientErrorException,
badActorTrustLine = this.adjustTrustlineFreeze(
issuerWallet,
badActorWallet,
- feeResult.drops().minimumFee(),
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee(),
FREEZE
);
assertThat(badActorTrustLine.freeze()).isTrue();
@@ -138,25 +139,25 @@ public void issueAndFreezeFundsIndividual() throws JsonRpcClientErrorException,
// Try to send funds from badActor to goodActor should not work because the badActor is frozen.
sendFunds(
- FIVE_THOUSAND, badActorWallet, goodActorWallet, feeResult.drops().minimumFee(),
+ FIVE_THOUSAND, badActorWallet, goodActorWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee(),
"tecPATH_DRY"
);
// Sending from the badActor to the issuer should still work
sendFunds(
- FIVE_THOUSAND, badActorWallet, issuerWallet, feeResult.drops().minimumFee()
+ FIVE_THOUSAND, badActorWallet, issuerWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
// Sending from the goodActor to the badActor should still work
sendFunds(
- FIVE_THOUSAND, goodActorWallet, badActorWallet, feeResult.drops().minimumFee()
+ FIVE_THOUSAND, goodActorWallet, badActorWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
// Unfreeze the bad actor.
badActorTrustLine = this.adjustTrustlineFreeze(
issuerWallet,
badActorWallet,
- feeResult.drops().minimumFee(),
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee(),
UN_FREEZE
);
assertThat(badActorTrustLine.freeze()).isTrue();
@@ -180,7 +181,7 @@ public void issueAndFreezeFundsGlobal() throws JsonRpcClientErrorException, Json
TrustLine badActorTrustLine = this.createTrustLine(
issuerWallet,
badActorWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
assertThat(badActorTrustLine.freeze()).isFalse();
assertThat(badActorTrustLine.freezePeer()).isFalse();
@@ -192,7 +193,7 @@ public void issueAndFreezeFundsGlobal() throws JsonRpcClientErrorException, Json
TrustLine goodActorTrustLine = this.createTrustLine(
issuerWallet,
goodActorWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
assertThat(goodActorTrustLine.freeze()).isFalse();
assertThat(goodActorTrustLine.freezePeer()).isFalse();
@@ -205,7 +206,7 @@ public void issueAndFreezeFundsGlobal() throws JsonRpcClientErrorException, Json
// Send funds from issuer to the badActor.
sendFunds(
- TEN_THOUSAND, issuerWallet, badActorWallet, feeResult.drops().minimumFee()
+ TEN_THOUSAND, issuerWallet, badActorWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
@@ -218,7 +219,7 @@ public void issueAndFreezeFundsGlobal() throws JsonRpcClientErrorException, Json
// Send funds from badActor to the goodActor.
sendFunds(
- FIVE_THOUSAND, badActorWallet, goodActorWallet, feeResult.drops().minimumFee()
+ FIVE_THOUSAND, badActorWallet, goodActorWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
@@ -232,7 +233,7 @@ public void issueAndFreezeFundsGlobal() throws JsonRpcClientErrorException, Json
// Global-Freeze the trustline for the issuer.
AccountInfoResult issuerAccountInfo = this.adjustGlobalTrustlineFreeze(
issuerWallet,
- feeResult.drops().minimumFee(),
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee(),
FREEZE
);
assertThat(issuerAccountInfo.accountData().flags().lsfGlobalFreeze()).isTrue();
@@ -246,43 +247,43 @@ public void issueAndFreezeFundsGlobal() throws JsonRpcClientErrorException, Json
// Try to send funds from badActor to goodActor should not work because the badActor is frozen.
sendFunds(
- "500", badActorWallet, goodActorWallet, feeResult.drops().minimumFee(),
+ "500", badActorWallet, goodActorWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee(),
"tecPATH_DRY"
);
// Sending from the goodActor to the badActor should not work
sendFunds(
- "500", goodActorWallet, badActorWallet, feeResult.drops().minimumFee(),
+ "500", goodActorWallet, badActorWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee(),
"tecPATH_DRY"
);
// Try to send funds from issuer to goodActor should work per
// https://xrpl.org/enact-global-freeze.html#intermission-while-frozen
sendFunds(
- "100", issuerWallet, goodActorWallet, feeResult.drops().minimumFee()
+ "100", issuerWallet, goodActorWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
// Try to send funds from issuer to badActor should work per
// https://xrpl.org/enact-global-freeze.html#intermission-while-frozen
sendFunds(
- "100", issuerWallet, badActorWallet, feeResult.drops().minimumFee()
+ "100", issuerWallet, badActorWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
// Try to send funds from issuer to goodActor should work per
// https://xrpl.org/enact-global-freeze.html#intermission-while-frozen
sendFunds(
- FIVE_THOUSAND, badActorWallet, issuerWallet, feeResult.drops().minimumFee()
+ FIVE_THOUSAND, badActorWallet, issuerWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
// Try to send funds from issuer to goodActor should work per
// https://xrpl.org/enact-global-freeze.html#intermission-while-frozen
sendFunds(
- FIVE_THOUSAND, goodActorWallet, issuerWallet, feeResult.drops().minimumFee()
+ FIVE_THOUSAND, goodActorWallet, issuerWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
// Unfreeze the bad actor.
issuerAccountInfo = this.adjustGlobalTrustlineFreeze(
issuerWallet,
- feeResult.drops().minimumFee(),
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee(),
UN_FREEZE
);
assertThat(issuerAccountInfo.accountData().flags().lsfGlobalFreeze()).isFalse();
@@ -427,7 +428,7 @@ protected void enableDefaultRipple(final Wallet wallet)
AccountSet accountSet = AccountSet.builder()
.sequence(issuerWalletAccountInfo.accountData().sequence())
.account(wallet.address())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.setFlag(AccountSetFlag.DEFAULT_RIPPLE)
.signingPublicKey(wallet.publicKey().base16Value())
.build();
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/IssuedCurrencyIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/IssuedCurrencyIT.java
index c993a47d5..d190abbaa 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/IssuedCurrencyIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/IssuedCurrencyIT.java
@@ -15,6 +15,7 @@
import org.xrpl.xrpl4j.model.client.accounts.TrustLine;
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.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.transactions.AccountSet;
import org.xrpl.xrpl4j.model.transactions.IssuedCurrencyAmount;
@@ -51,7 +52,7 @@ void createTrustlineWithMaxLimit() throws JsonRpcClientErrorException, JsonProce
IssuedCurrencyAmount.MAX_VALUE,
issuerWallet,
counterpartyWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
assertThat(trustLine.limitPeer()).isEqualTo("9999999999999999e80");
@@ -76,7 +77,7 @@ void createTrustlineWithMaxLimitMinusOneExponent() throws JsonRpcClientErrorExce
new BigDecimal(IssuedCurrencyAmount.MAX_VALUE).scaleByPowerOfTen(-1).toEngineeringString(),
issuerWallet,
counterpartyWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
assertThat(trustLine.limitPeer()).isEqualTo("9999999999999999e79");
@@ -101,7 +102,7 @@ void createTrustlineWithSmallestPositiveLimit() throws JsonRpcClientErrorExcepti
IssuedCurrencyAmount.MIN_POSITIVE_VALUE,
issuerWallet,
counterpartyWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
assertThat(trustLine.limitPeer()).isEqualTo("1000000000000000e-96");
@@ -128,7 +129,7 @@ void createTrustlineWithSmalletPositiveLimitPlusOne() throws JsonRpcClientErrorE
limitValue.toString(),
issuerWallet,
counterpartyWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
assertThat(trustLine.limitPeer()).isEqualTo("1100000000000000e-96");
@@ -153,12 +154,15 @@ public void issueIssuedCurrencyBalance() throws JsonRpcClientErrorException, Jso
"10000",
issuerWallet,
counterpartyWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
// Send some xrpl4jCoin to the counterparty account.
- issueBalance(xrpl4jCoin, trustLine.limitPeer(), issuerWallet, counterpartyWallet, feeResult.drops().minimumFee());
+ issueBalance(
+ xrpl4jCoin, trustLine.limitPeer(), issuerWallet, counterpartyWallet,
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
+ );
///////////////////////////
// Validate that the TrustLine balance was updated as a result of the Payment.
@@ -203,7 +207,7 @@ public void sendSimpleRipplingIssuedCurrencyPayment() throws JsonRpcClientErrorE
"10000",
issuerWallet,
aliceWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
@@ -213,16 +217,16 @@ public void sendSimpleRipplingIssuedCurrencyPayment() throws JsonRpcClientErrorE
"10000",
issuerWallet,
bobWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
// Issuer issues 50 USD to alice
- issueBalance("USD", "50", issuerWallet, aliceWallet, feeResult.drops().minimumFee());
+ issueBalance("USD", "50", issuerWallet, aliceWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee());
///////////////////////////
// Issuer issues 50 USD to bob
- issueBalance("USD", "50", issuerWallet, bobWallet, feeResult.drops().minimumFee());
+ issueBalance("USD", "50", issuerWallet, bobWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee());
///////////////////////////
// Try to find a path for this Payment.
@@ -245,7 +249,7 @@ public void sendSimpleRipplingIssuedCurrencyPayment() throws JsonRpcClientErrorE
AccountInfoResult aliceAccountInfo = getValidatedAccountInfo(aliceWallet.address());
Payment aliceToBobPayment = Payment.builder()
.account(aliceWallet.address())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(aliceAccountInfo.accountData().sequence())
.destination(bobWallet.address())
.amount(IssuedCurrencyAmount.builder()
@@ -316,7 +320,7 @@ public void sendMultiHopSameCurrencyPayment() throws JsonRpcClientErrorException
"10000",
issuerAWallet,
charlieWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
@@ -326,7 +330,7 @@ public void sendMultiHopSameCurrencyPayment() throws JsonRpcClientErrorException
"10000",
issuerAWallet,
emilyWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
@@ -336,7 +340,7 @@ public void sendMultiHopSameCurrencyPayment() throws JsonRpcClientErrorException
"10000",
issuerBWallet,
emilyWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
@@ -346,28 +350,28 @@ public void sendMultiHopSameCurrencyPayment() throws JsonRpcClientErrorException
"10000",
issuerBWallet,
danielWallet,
- feeResult.drops().minimumFee()
+ FeeUtils.computeNetworkFees(feeResult).recommendedFee()
);
///////////////////////////
// Issue 10 USD from issuerA to charlie.
// IssuerA now owes Charlie 10 USD.
- issueBalance("USD", "10", issuerAWallet, charlieWallet, feeResult.drops().minimumFee());
+ issueBalance("USD", "10", issuerAWallet, charlieWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee());
///////////////////////////
// Issue 1 USD from issuerA to emily.
// IssuerA now owes Emily 1 USD
- issueBalance("USD", "1", issuerAWallet, emilyWallet, feeResult.drops().minimumFee());
+ issueBalance("USD", "1", issuerAWallet, emilyWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee());
///////////////////////////
// Issue 100 USD from issuerB to emily.
// IssuerB now owes Emily 100 USD
- issueBalance("USD", "100", issuerBWallet, emilyWallet, feeResult.drops().minimumFee());
+ issueBalance("USD", "100", issuerBWallet, emilyWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee());
///////////////////////////
// Issue 2 USD from issuerB to daniel.
// IssuerB now owes Daniel 2 USD
- issueBalance("USD", "2", issuerBWallet, danielWallet, feeResult.drops().minimumFee());
+ issueBalance("USD", "2", issuerBWallet, danielWallet, FeeUtils.computeNetworkFees(feeResult).recommendedFee());
///////////////////////////
// Look for a payment path from charlie to daniel.
@@ -398,7 +402,7 @@ public void sendMultiHopSameCurrencyPayment() throws JsonRpcClientErrorException
AccountInfoResult charlieAccountInfo = getValidatedAccountInfo(charlieWallet.address());
Payment charlieToDanielPayment = Payment.builder()
.account(charlieWallet.address())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(charlieAccountInfo.accountData().sequence())
.destination(danielWallet.address())
.amount(IssuedCurrencyAmount.builder()
@@ -464,7 +468,7 @@ public void setDefaultRipple(Wallet issuerWallet, FeeResult feeResult)
AccountSet setDefaultRipple = AccountSet.builder()
.account(issuerWallet.address())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(issuerAccountInfo.accountData().sequence())
.signingPublicKey(issuerWallet.publicKey().base16Value())
.setFlag(AccountSet.AccountSetFlag.DEFAULT_RIPPLE)
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/OfferIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/OfferIT.java
index 13994a6ef..fdad3d33a 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/OfferIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/OfferIT.java
@@ -14,6 +14,7 @@
import org.xrpl.xrpl4j.crypto.core.wallet.Wallet;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.flags.Flags;
import org.xrpl.xrpl4j.model.ledger.OfferObject;
@@ -61,7 +62,7 @@ public void ensureUsdIssued() throws JsonRpcClientErrorException, JsonProcessing
UnsignedInteger sequence = accountInfoResult.accountData().sequence();
OfferCreate offerCreate = OfferCreate.builder()
.account(issuerWallet.address())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.signingPublicKey(issuerWallet.publicKey().base16Value())
.takerGets(IssuedCurrencyAmount.builder()
@@ -111,7 +112,7 @@ public void createOpenOfferAndCancel() throws JsonRpcClientErrorException, JsonP
UnsignedInteger sequence = accountInfoResult.accountData().sequence();
OfferCreate offerCreate = OfferCreate.builder()
.account(purchaser.address())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.signingPublicKey(purchaser.publicKey().base16Value())
.takerPays(IssuedCurrencyAmount.builder()
@@ -165,9 +166,11 @@ private void cancelOffer(
AccountInfoResult infoResult = this.scanForResult(() -> this.getValidatedAccountInfo(purchaser.address()));
UnsignedInteger nextSequence = infoResult.accountData().sequence();
+ FeeResult feeResult = xrplClient.fee();
+
OfferCancel offerCancel = OfferCancel.builder()
.account(purchaser.address())
- .fee(xrplClient.fee().drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(nextSequence)
.offerSequence(offerSequence)
.signingPublicKey(purchaser.publicKey().base16Value())
@@ -202,7 +205,7 @@ public void createUnmatchedKillOrFill() throws JsonRpcClientErrorException, Json
UnsignedInteger sequence = accountInfoResult.accountData().sequence();
OfferCreate offerCreate = OfferCreate.builder()
.account(purchaser.address())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.signingPublicKey(purchaser.publicKey().base16Value())
.takerPays(IssuedCurrencyAmount.builder()
@@ -270,7 +273,7 @@ public void createFullyMatchedOffer() throws JsonRpcClientErrorException, JsonPr
OfferCreate offerCreate = OfferCreate.builder()
.account(purchaser.address())
- .fee(feeResult.drops().minimumFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sequence)
.signingPublicKey(purchaser.publicKey().base16Value())
.takerPays(requestCurrencyAmount)
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/PaymentChannelIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/PaymentChannelIT.java
index 8529b1928..64eba6b03 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/PaymentChannelIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/PaymentChannelIT.java
@@ -19,6 +19,7 @@
import org.xrpl.xrpl4j.model.client.channels.UnsignedClaim;
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.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.ledger.PayChannelObject;
import org.xrpl.xrpl4j.model.transactions.PaymentChannelClaim;
@@ -52,7 +53,7 @@ public void createPaymentChannel() throws JsonRpcClientErrorException, JsonProce
// the source and destination accounts
PaymentChannelCreate paymentChannelCreate = PaymentChannelCreate.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(10000))
.destination(destinationWallet.address())
@@ -138,7 +139,7 @@ void createAndClaimPaymentChannel() throws JsonRpcClientErrorException, JsonProc
// the source and destination accounts
PaymentChannelCreate paymentChannelCreate = PaymentChannelCreate.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(10000000))
.destination(destinationWallet.address())
@@ -207,7 +208,7 @@ void createAndClaimPaymentChannel() throws JsonRpcClientErrorException, JsonProc
// Destination account submits the signed claim to the ledger to get their XRP
PaymentChannelClaim paymentChannelClaim = PaymentChannelClaim.builder()
.account(destinationWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(destinationAccountInfo.accountData().sequence())
.channel(paymentChannel.channelId())
.balance(paymentChannel.balance().plus(unsignedClaim.amount()))
@@ -256,7 +257,7 @@ void createAddFundsAndSetExpirationToPaymentChannel() throws JsonRpcClientErrorE
// the source and destination accounts
PaymentChannelCreate paymentChannelCreate = PaymentChannelCreate.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(10000000))
.destination(destinationWallet.address())
@@ -298,7 +299,7 @@ void createAddFundsAndSetExpirationToPaymentChannel() throws JsonRpcClientErrorE
PaymentChannelFund paymentChannelFund = PaymentChannelFund.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence().plus(UnsignedInteger.ONE))
.signingPublicKey(sourceWallet.publicKey().base16Value())
.channel(paymentChannel.channelId())
@@ -338,7 +339,7 @@ void createAddFundsAndSetExpirationToPaymentChannel() throws JsonRpcClientErrorE
PaymentChannelFund paymentChannelFundWithNewExpiry = PaymentChannelFund.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence().plus(UnsignedInteger.valueOf(2)))
.signingPublicKey(sourceWallet.publicKey().base16Value())
.channel(paymentChannel.channelId())
@@ -389,7 +390,7 @@ void testCurrentAccountChannels() throws JsonRpcClientErrorException, JsonProces
// the source and destination accounts
PaymentChannelCreate createPaymentChannel = PaymentChannelCreate.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(senderAccountInfo.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(10000))
.destination(destinationWallet.address())
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SetRegularKeyIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SetRegularKeyIT.java
index d73d50931..4a37ddd64 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SetRegularKeyIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SetRegularKeyIT.java
@@ -10,6 +10,7 @@
import org.xrpl.xrpl4j.crypto.core.wallet.Wallet;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.transactions.AccountSet;
import org.xrpl.xrpl4j.model.transactions.SetRegularKey;
@@ -39,7 +40,7 @@ void setRegularKeyOnAccount() throws JsonRpcClientErrorException, JsonProcessing
FeeResult feeResult = xrplClient.fee();
SetRegularKey setRegularKey = SetRegularKey.builder()
.account(wallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.regularKey(newWallet.address())
.signingPublicKey(wallet.publicKey().base16Value())
@@ -63,7 +64,7 @@ void setRegularKeyOnAccount() throws JsonRpcClientErrorException, JsonProcessing
() -> {
AccountSet accountSet = AccountSet.builder()
.account(wallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence().plus(UnsignedInteger.ONE))
.signingPublicKey(newWallet.publicKey().base16Value())
.build();
@@ -100,7 +101,7 @@ void removeRegularKeyFromAccount() throws JsonRpcClientErrorException, JsonProce
FeeResult feeResult = xrplClient.fee();
SetRegularKey setRegularKey = SetRegularKey.builder()
.account(wallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.regularKey(newWallet.address())
.signingPublicKey(wallet.publicKey().base16Value())
@@ -124,7 +125,7 @@ void removeRegularKeyFromAccount() throws JsonRpcClientErrorException, JsonProce
() -> {
AccountSet accountSet = AccountSet.builder()
.account(wallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence().plus(UnsignedInteger.ONE))
.signingPublicKey(newWallet.publicKey().base16Value())
.build();
@@ -142,7 +143,7 @@ void removeRegularKeyFromAccount() throws JsonRpcClientErrorException, JsonProce
SetRegularKey removeRegularKey = SetRegularKey.builder()
.account(wallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence().plus(UnsignedInteger.valueOf(2)))
.signingPublicKey(wallet.publicKey().base16Value())
.build();
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SignerListSetIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SignerListSetIT.java
index 6700ae283..e066eb51f 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SignerListSetIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SignerListSetIT.java
@@ -12,6 +12,7 @@
import org.xrpl.xrpl4j.crypto.core.wallet.Wallet;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitMultiSignedResult;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.ledger.SignerEntry;
@@ -20,7 +21,6 @@
import org.xrpl.xrpl4j.model.transactions.Signer;
import org.xrpl.xrpl4j.model.transactions.SignerListSet;
import org.xrpl.xrpl4j.model.transactions.SignerWrapper;
-import org.xrpl.xrpl4j.model.transactions.Transaction;
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
import java.util.Comparator;
@@ -60,7 +60,7 @@ void addSignersToSignerListAndSendPayment() throws JsonRpcClientErrorException,
FeeResult feeResult = xrplClient.fee();
SignerListSet signerListSet = SignerListSet.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sourceAccountInfo.accountData().sequence())
.signerQuorum(UnsignedInteger.valueOf(2))
.addSignerEntries(
@@ -112,10 +112,10 @@ void addSignersToSignerListAndSendPayment() throws JsonRpcClientErrorException,
Payment unsignedPayment = Payment.builder()
.account(sourceWallet.address())
.fee(
- Transaction.computeMultiSigFee(
- feeResult.drops().openLedgerFee(),
+ FeeUtils.computeMultisigNetworkFees(
+ feeResult,
sourceAccountInfoAfterSignerListSet.accountData().signerLists().get(0)
- )
+ ).recommendedFee()
)
.sequence(sourceAccountInfoAfterSignerListSet.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(12345))
@@ -178,7 +178,7 @@ void addSignersToSignerListThenDeleteSignerList() throws JsonRpcClientErrorExcep
FeeResult feeResult = xrplClient.fee();
SignerListSet signerListSet = SignerListSet.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sourceAccountInfo.accountData().sequence())
.signerQuorum(UnsignedInteger.valueOf(2))
.addSignerEntries(
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SubmitPaymentIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SubmitPaymentIT.java
index 9c4a0d472..13d550a42 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SubmitPaymentIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/SubmitPaymentIT.java
@@ -12,6 +12,7 @@
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
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.LedgerRequestParams;
import org.xrpl.xrpl4j.model.client.ledger.LedgerResult;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
@@ -40,7 +41,7 @@ public void sendPayment() throws JsonRpcClientErrorException, JsonProcessingExce
XrpCurrencyAmount amount = XrpCurrencyAmount.ofDrops(12345);
Payment payment = Payment.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.address())
.amount(amount)
@@ -80,7 +81,7 @@ public void sendPaymentFromSecp256k1Wallet() throws JsonRpcClientErrorException,
Payment payment = Payment.builder()
.account(senderWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWallet.address())
.amount(XrpCurrencyAmount.ofDrops(12345))
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/TransactUsingDelegatedSignatureService.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/TransactUsingDelegatedSignatureService.java
index 10f4eea3e..547a5859d 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/TransactUsingDelegatedSignatureService.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/TransactUsingDelegatedSignatureService.java
@@ -15,6 +15,7 @@
import org.xrpl.xrpl4j.crypto.core.signing.SingleSingedTransaction;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitMultiSignedResult;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.ledger.SignerEntry;
@@ -24,7 +25,6 @@
import org.xrpl.xrpl4j.model.transactions.Signer;
import org.xrpl.xrpl4j.model.transactions.SignerListSet;
import org.xrpl.xrpl4j.model.transactions.SignerWrapper;
-import org.xrpl.xrpl4j.model.transactions.Transaction;
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
import java.util.Comparator;
@@ -54,7 +54,7 @@ public void sendPaymentFromEd25519Account() throws JsonRpcClientErrorException,
AccountInfoResult accountInfo = this.scanForResult(() -> this.getValidatedAccountInfo(sourceWalletAddress));
Payment payment = Payment.builder()
.account(sourceWalletAddress)
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWalletAddress)
.amount(XrpCurrencyAmount.ofDrops(12345))
@@ -88,7 +88,7 @@ public void sendPaymentFromSecp256k1Account() throws JsonRpcClientErrorException
.scanForResult(() -> this.getValidatedAccountInfo(sourceWalletAddress));
Payment payment = Payment.builder()
.account(sourceWalletAddress)
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWalletAddress)
.amount(XrpCurrencyAmount.ofDrops(12345))
@@ -169,7 +169,7 @@ private void multiSigSendPaymentHelper(final DelegatedSignatureService delegated
FeeResult feeResult = xrplClient.fee();
SignerListSet signerListSet = SignerListSet.builder()
.account(sourceAddress)
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sourceAccountInfo.accountData().sequence())
.signerQuorum(UnsignedInteger.valueOf(2))
.addSignerEntries(
@@ -221,10 +221,10 @@ private void multiSigSendPaymentHelper(final DelegatedSignatureService delegated
Payment unsignedPayment = Payment.builder()
.account(sourceAddress)
.fee(
- Transaction.computeMultiSigFee(
- feeResult.drops().openLedgerFee(),
+ FeeUtils.computeMultisigNetworkFees(
+ feeResult,
sourceAccountInfoAfterSignerListSet.accountData().signerLists().get(0)
- )
+ ).recommendedFee()
)
.sequence(sourceAccountInfoAfterSignerListSet.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(12345))
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/TransactUsingSignatureService.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/TransactUsingSignatureService.java
index bbc7e9088..461e01aac 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/TransactUsingSignatureService.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/TransactUsingSignatureService.java
@@ -18,6 +18,7 @@
import org.xrpl.xrpl4j.crypto.core.wallet.Wallet;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoResult;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
+import org.xrpl.xrpl4j.model.client.fees.FeeUtils;
import org.xrpl.xrpl4j.model.client.transactions.SubmitMultiSignedResult;
import org.xrpl.xrpl4j.model.client.transactions.SubmitResult;
import org.xrpl.xrpl4j.model.ledger.SignerEntry;
@@ -27,7 +28,6 @@
import org.xrpl.xrpl4j.model.transactions.Signer;
import org.xrpl.xrpl4j.model.transactions.SignerListSet;
import org.xrpl.xrpl4j.model.transactions.SignerWrapper;
-import org.xrpl.xrpl4j.model.transactions.Transaction;
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
import java.util.Comparator;
@@ -64,7 +64,7 @@ public void sendPaymentFromEd25519Wallet() throws JsonRpcClientErrorException, J
AccountInfoResult accountInfo = this.scanForResult(() -> this.getValidatedAccountInfo(sourceWalletAddress));
Payment payment = Payment.builder()
.account(sourceWalletAddress)
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWalletAddress)
.amount(XrpCurrencyAmount.ofDrops(12345))
@@ -98,7 +98,7 @@ public void sendPaymentFromSecp256k1Wallet() throws JsonRpcClientErrorException,
.scanForResult(() -> this.getValidatedAccountInfo(sourceWalletAddress));
Payment payment = Payment.builder()
.account(sourceWalletAddress)
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(accountInfo.accountData().sequence())
.destination(destinationWalletAddress)
.amount(XrpCurrencyAmount.ofDrops(12345))
@@ -173,7 +173,7 @@ private void multiSigSendPaymentHelper(
FeeResult feeResult = xrplClient.fee();
SignerListSet signerListSet = SignerListSet.builder()
.account(sourceWallet.address())
- .fee(feeResult.drops().openLedgerFee())
+ .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee())
.sequence(sourceAccountInfo.accountData().sequence())
.signerQuorum(UnsignedInteger.valueOf(2))
.addSignerEntries(
@@ -225,10 +225,10 @@ private void multiSigSendPaymentHelper(
Payment unsignedPayment = Payment.builder()
.account(sourceWallet.address())
.fee(
- Transaction.computeMultiSigFee(
- feeResult.drops().openLedgerFee(),
+ FeeUtils.computeMultisigNetworkFees(
+ feeResult,
sourceAccountInfoAfterSignerListSet.accountData().signerLists().get(0)
- )
+ ).recommendedFee()
)
.sequence(sourceAccountInfoAfterSignerListSet.accountData().sequence())
.amount(XrpCurrencyAmount.ofDrops(12345))
diff --git a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/accounts/AccountCurrenciesRequestParams.java b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/accounts/AccountCurrenciesRequestParams.java
index 9430427c6..1a25b8c8e 100644
--- a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/accounts/AccountCurrenciesRequestParams.java
+++ b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/accounts/AccountCurrenciesRequestParams.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.
@@ -28,7 +28,6 @@
import org.xrpl.xrpl4j.model.client.LegacyLedgerSpecifierUtils;
import org.xrpl.xrpl4j.model.client.XrplRequestParams;
import org.xrpl.xrpl4j.model.client.common.LedgerIndex;
-import org.xrpl.xrpl4j.model.client.common.LedgerIndexShortcut;
import org.xrpl.xrpl4j.model.client.common.LedgerSpecifier;
import org.xrpl.xrpl4j.model.transactions.Address;
import org.xrpl.xrpl4j.model.transactions.Hash256;
@@ -44,6 +43,11 @@
@JsonDeserialize(as = ImmutableAccountCurrenciesRequestParams.class)
public interface AccountCurrenciesRequestParams extends XrplRequestParams {
+ /**
+ * Builder for {@link AccountCurrenciesRequestParams}.
+ *
+ * @return A {@link ImmutableAccountCurrenciesRequestParams.Builder}.
+ */
static ImmutableAccountCurrenciesRequestParams.Builder builder() {
return ImmutableAccountCurrenciesRequestParams.builder();
}
@@ -59,6 +63,7 @@ static ImmutableAccountCurrenciesRequestParams.Builder builder() {
* A 20-byte hex string for the ledger version to use.
*
* @return An optionally-present {@link Hash256}.
+ *
* @deprecated Ledger hash should be specified in {@link #ledgerSpecifier()}.
*/
@JsonIgnore
@@ -70,6 +75,7 @@ static ImmutableAccountCurrenciesRequestParams.Builder builder() {
* The ledger index of the ledger to use, or a shortcut string to choose a ledger automatically.
*
* @return A {@link LedgerIndex}. Defaults to {@link LedgerIndex#CURRENT}.
+ *
* @deprecated Ledger index and any shortcut values should be specified in {@link #ledgerSpecifier()}.
*/
@JsonIgnore
@@ -79,8 +85,8 @@ static ImmutableAccountCurrenciesRequestParams.Builder builder() {
LedgerIndex ledgerIndex();
/**
- * Specifies the ledger version to request. A ledger version can be specified by ledger hash,
- * numerical ledger index, or a shortcut value.
+ * Specifies the ledger version to request. A ledger version can be specified by ledger hash, numerical ledger index,
+ * or a shortcut value.
*
* @return A {@link LedgerSpecifier} specifying the ledger version to request.
*/
diff --git a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/ComputedNetworkFees.java b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/ComputedNetworkFees.java
new file mode 100644
index 000000000..bda1ada78
--- /dev/null
+++ b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/ComputedNetworkFees.java
@@ -0,0 +1,91 @@
+package org.xrpl.xrpl4j.model.client.fees;
+
+import org.immutables.value.Value;
+import org.immutables.value.Value.Derived;
+import org.xrpl.xrpl4j.model.immutables.FluentCompareTo;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+import java.math.BigDecimal;
+
+/**
+ * An object that holds fee options that were calculated based upon current ledger stats.
+ */
+@Value.Immutable
+public interface ComputedNetworkFees {
+
+ /**
+ * A builder of for {@link ComputedNetworkFees}.
+ *
+ * @return An {@link ImmutableComputedNetworkFees.Builder}.
+ */
+ static ImmutableComputedNetworkFees.Builder builder() {
+ return ImmutableComputedNetworkFees.builder();
+ }
+
+ /**
+ * The `low` fee, which is the fee that should be used if the transaction queue is empty.
+ *
+ * @return An {@link XrpCurrencyAmount} representing the `low` fee (in drops).
+ */
+ XrpCurrencyAmount feeLow();
+
+ /**
+ * The `medium` fee, which is the fee that should be used if the transaction queue is neither empty nor full.
+ *
+ * @return An {@link XrpCurrencyAmount} representing the `medium` fee (in drops).
+ */
+ XrpCurrencyAmount feeMedium();
+
+ /**
+ * The `high` fee, which is the fee that should be used if the transaction queue is full.
+ *
+ * @return An {@link XrpCurrencyAmount} representing the `high` fee (in drops).
+ */
+ XrpCurrencyAmount feeHigh();
+
+ /**
+ * Measures the fullness of the transaction queue by representing the percent full that the queue is. For example, if
+ * the transaction queue can hold two transactions, and one is in the queue, then this value would be 50%, or 0.5.
+ *
+ * @return A {@link BigDecimal}.
+ */
+ // TODO: Introduce Percentage.
+ BigDecimal queuePercentage();
+
+ /**
+ * Helper method to return the recommened fee to use.
+ *
+ * @return An {@link XrpCurrencyAmount} that is the recommended fee.
+ */
+ @Derived
+ default XrpCurrencyAmount recommendedFee() {
+ if (isTransactionQueueEmpty()) {
+ return feeLow();
+ } else if (isTranactionQueueFull()) {
+ return feeHigh();
+ } else { // queue is neither empty nor full
+ return feeMedium();
+ }
+ }
+
+ /**
+ * Determines if the transaction queue is full.
+ *
+ * @return {@code true} if the transaction queue is full; {@code false} otherwise.
+ */
+ @Derived
+ default boolean isTranactionQueueFull() {
+ return FluentCompareTo.is(queuePercentage()).greaterThanEqualTo(BigDecimal.ONE);
+ }
+
+ /**
+ * Helper method to determine if a transaction queue is empty.
+ *
+ * @return {@code true} if the queue is empty; {@code false} otherwise.
+ */
+ @Derived
+ default boolean isTransactionQueueEmpty() {
+ return FluentCompareTo.is(queuePercentage()).lessThanOrEqualTo(BigDecimal.ZERO);
+ }
+
+}
diff --git a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeResult.java b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeResult.java
index 375d9cb45..6e6701751 100644
--- a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeResult.java
+++ b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeResult.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.
@@ -33,8 +33,8 @@
import java.util.Optional;
/**
- * The result of a "fee" rippled API call, which reports the current state of the open-ledger requirements
- * for the transaction cost.
+ * The result of a "fee" rippled API call, which reports the current state of the open-ledger requirements for the
+ * transaction cost.
*/
@Immutable
@JsonSerialize(as = ImmutableFeeResult.class)
@@ -78,8 +78,8 @@ static ImmutableFeeResult.Builder builder() {
FeeDrops drops();
/**
- * The approximate number of transactions expected to be included in the current ledger.
- * This is based on the number of transactions in the previous ledger.
+ * The approximate number of transactions expected to be included in the current ledger. This is based on the number
+ * of transactions in the previous ledger.
*
* @return An {@link UnsignedInteger} denoting the expected ledger size.
*/
@@ -106,8 +106,8 @@ static ImmutableFeeResult.Builder builder() {
FeeLevels levels();
/**
- * The maximum number of transactions that the transaction queue can currently hold.
- * Optional because this may not be present on older versions of rippled.
+ * The maximum number of transactions that the transaction queue can currently hold. Optional because this may not be
+ * present on older versions of rippled.
*
* @return An optionally-present {@link UnsignedInteger} denoting the maximum queue size.
*/
diff --git a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeUtils.java b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeUtils.java
new file mode 100644
index 000000000..cf5c6002c
--- /dev/null
+++ b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/client/fees/FeeUtils.java
@@ -0,0 +1,432 @@
+package org.xrpl.xrpl4j.model.client.fees;
+
+import static org.xrpl.xrpl4j.model.transactions.CurrencyAmount.MAX_XRP_IN_DROPS;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.immutables.value.Value.Derived;
+import org.immutables.value.Value.Immutable;
+import org.xrpl.xrpl4j.model.immutables.FluentCompareTo;
+import org.xrpl.xrpl4j.model.ledger.SignerListObject;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Utils relating to XRPL fees.
+ */
+public class FeeUtils {
+
+ private static final BigInteger MAX_UNSIGNED_LONG = UnsignedLong.MAX_VALUE.bigIntegerValue();
+
+ private static final BigDecimal ONE_POINT_ONE = new BigDecimal("1.1");
+
+ private static final BigDecimal ZERO_POINT_ONE = new BigDecimal("0.1");
+
+ private static final BigInteger FIVE_HUNDRED = BigInteger.valueOf(500);
+
+ private static final BigDecimal TWO = new BigDecimal(2);
+
+ private static final BigDecimal THREE = new BigDecimal(3);
+
+ private static final BigInteger FIFTEEN = BigInteger.valueOf(15);
+
+ private static final BigInteger TEN_THOUSAND = BigInteger.valueOf(10000);
+
+ private static final BigInteger ONE_THOUSAND = BigInteger.valueOf(1000);
+
+
+ /**
+ * Computes the fee necessary for a multisigned transaction.
+ *
+ * The transaction cost of a multisigned transaction must be at least {@code (N + 1) * (the normal
+ * transaction cost)}, where {@code N} is the number of signatures provided.
+ *
+ * @param feeResult {@link FeeResult} object obtained by querying the ledger (e.g., via an `XrplClient#fee()` call).
+ * @param signerList The {@link SignerListObject} containing the signers of the transaction.
+ *
+ * @return An {@link XrpCurrencyAmount} representing the multisig fee.
+ */
+ public static ComputedNetworkFees computeMultisigNetworkFees(
+ final FeeResult feeResult,
+ final SignerListObject signerList
+ ) {
+ Objects.requireNonNull(feeResult);
+ Objects.requireNonNull(signerList);
+
+ ComputedNetworkFees computedNetworkFees = computeNetworkFees(feeResult);
+ XrpCurrencyAmount numberOfSignersAsAmount = XrpCurrencyAmount.of(
+ UnsignedLong.valueOf(signerList.signerEntries().size() + 1)
+ );
+ return ComputedNetworkFees.builder()
+ .feeLow(computedNetworkFees.feeLow().times(numberOfSignersAsAmount))
+ .feeMedium(computedNetworkFees.feeMedium().times(numberOfSignersAsAmount))
+ .feeHigh(computedNetworkFees.feeHigh().times(numberOfSignersAsAmount))
+ .queuePercentage(computedNetworkFees.queuePercentage())
+ .build();
+ }
+
+ /**
+ * Calculate a suggested fee to be used for submitting a transaction to the XRPL. The calculated value depends on the
+ * current size of the job queue as compared to its total capacity.
+ *
+ * @param feeResult {@link FeeResult} object obtained by querying the ledger (e.g., via an `XrplClient#fee()` call).
+ *
+ * @return {@link ComputedNetworkFees} with low, medium and high fee levels to choose from for the transaction.
+ *
+ * @see "https://xrpl.org/fee.html"
+ * @see "https://github.com/XRPL-Labs/XUMM-App/blob/master/src/services/LedgerService.ts#L244"
+ */
+ public static ComputedNetworkFees computeNetworkFees(final FeeResult feeResult) {
+ Objects.requireNonNull(feeResult);
+
+ final DecomposedFees decomposedFees = DecomposedFees.builder(feeResult);
+ final XrpCurrencyAmount feeLow = computeFeeLow(decomposedFees);
+
+ return ComputedNetworkFees.builder()
+ .feeLow(feeLow)
+ .feeMedium(computeFeeMedium(decomposedFees, feeLow))
+ .feeHigh(computeFeeHigh(decomposedFees))
+ .queuePercentage(decomposedFees.queuePercentage())
+ .build();
+ }
+
+ /**
+ * Calculate the lowest fee the user is able to pay if the queue is empty.
+ *
+ * @param decomposedFees A {@link DecomposedFees} that contains information about current XRPL fees.
+ *
+ * @return An {@link XrpCurrencyAmount} representing the `low` fee.
+ */
+ private static XrpCurrencyAmount computeFeeLow(final DecomposedFees decomposedFees) {
+ Objects.requireNonNull(decomposedFees);
+
+ final BigInteger adjustedMinimumFeeDrops = decomposedFees.adjustedMinimumFeeDrops();
+ final BigInteger medianFee = decomposedFees.medianFeeDrops();
+ final BigInteger openLedgerFee = decomposedFees.openLedgerFeeDrops();
+
+ // Cap `feeLow` to the size of an UnsignedLong.
+ return XrpCurrencyAmount.ofDrops(
+ toUnsignedLongSafe(
+ min(
+ max(
+ adjustedMinimumFeeDrops, // min fee * 1.50
+ divideToBigInteger(max(medianFee, openLedgerFee), FIVE_HUNDRED)
+ ),
+ ONE_THOUSAND
+ )
+ )
+ );
+ }
+
+ /**
+ * Compute the `medium` fee, which is the fee to use when the transaction queue is neither empty nor full.
+ *
+ * @param decomposedFees A {@link DecomposedFees} with precomputed values to use.
+ * @param feeLow The computed `low` fee as found in {@link #computeFeeLow(DecomposedFees)}.
+ *
+ * @return An {@link UnsignedLong} representing the `medium` fee.
+ */
+ private static XrpCurrencyAmount computeFeeMedium(final DecomposedFees decomposedFees,
+ final XrpCurrencyAmount feeLow) {
+ Objects.requireNonNull(decomposedFees);
+ Objects.requireNonNull(feeLow);
+
+ final BigInteger minimumFee = decomposedFees.adjustedMinimumFeeDrops();
+ final BigDecimal minimumFeeBd = decomposedFees.adjustedMinimumFeeDropsAsBigDecimal();
+ final BigDecimal medianFeeBd = decomposedFees.medianFeeDropsAsBigDecimal();
+ final BigDecimal queuePercentage = decomposedFees.queuePercentage();
+
+ final BigInteger possibleFeeMedium;
+ if (FluentCompareTo.is(queuePercentage).greaterThan(ZERO_POINT_ONE)) {
+ possibleFeeMedium = minimumFeeBd
+ .add(medianFeeBd)
+ .add(decomposedFees.openLedgerFeeDropsAsBigDecimal())
+ .divide(THREE, 0, RoundingMode.HALF_UP)
+ .toBigIntegerExact();
+ } else { // 0 > `queuePercentage` < 0.1
+ // Note: `computeFeeMedium` is not called if `queuePercentage` is 0, so we omit that check even though it's in
+ // the original xumm code.
+ possibleFeeMedium = max(minimumFee.multiply(BigInteger.TEN),
+ minimumFeeBd.add(medianFeeBd).divide(TWO, 0, RoundingMode.HALF_UP).toBigIntegerExact());
+ }
+
+ // calculate the lowest fee the user is able to pay if there are txns in the queue
+ final BigInteger feeMedium = min(
+ possibleFeeMedium,
+ feeLow.value().bigIntegerValue().multiply(FIFTEEN), TEN_THOUSAND
+ );
+
+ return XrpCurrencyAmount.ofDrops(
+ toUnsignedLongSafe(feeMedium)
+ );
+ }
+
+ /**
+ * Compute the `high` fee, which is the fee to use when the transaction queue is full.
+ *
+ * @param decomposedFees A {@link DecomposedFees} with precomputed values to use.
+ *
+ * @return An {@link UnsignedLong} representing the `high` fee.
+ */
+ private static XrpCurrencyAmount computeFeeHigh(final DecomposedFees decomposedFees) {
+ Objects.requireNonNull(decomposedFees);
+
+ final BigInteger minimumFee = decomposedFees.adjustedMinimumFeeDrops();
+ final BigInteger medianFee = decomposedFees.medianFeeDrops();
+ final BigInteger openLedgerFee = decomposedFees.openLedgerFeeDrops();
+
+ final BigInteger feeHigh = min(
+ max(minimumFee.multiply(BigInteger.TEN), multiplyToBigInteger(max(medianFee, openLedgerFee), ONE_POINT_ONE)),
+ TEN_THOUSAND);
+ return XrpCurrencyAmount.ofDrops(
+ toUnsignedLongSafe(feeHigh)
+ );
+ }
+
+ /**
+ * Helper method to determine if a transaction queue is empty by inspecting a `percent-full` measurement.
+ *
+ * @param queuePercentage A {@link BigDecimal} representing the percent-full value for a tx queue.
+ *
+ * @return {@code true} if the queue is empty; {@code false} otherwise.
+ */
+ @VisibleForTesting
+ public static boolean queueIsEmpty(final BigDecimal queuePercentage) {
+ Objects.requireNonNull(queuePercentage);
+ return FluentCompareTo.is(queuePercentage).lessThanOrEqualTo(BigDecimal.ZERO);
+ }
+
+ /**
+ * Helper method to determine if a transaction queue is both non-empty, but not completely full, by inspecting a
+ * `percent-full` measurement.
+ *
+ * @param queuePercentage A {@link BigDecimal} representing the percent-full value for a tx queue.
+ *
+ * @return {@code true} if the queue is empty; {@code false} otherwise.
+ */
+ @VisibleForTesting
+ public static boolean queueIsNotEmptyAndNotFull(final BigDecimal queuePercentage) {
+ Objects.requireNonNull(queuePercentage);
+ return FluentCompareTo.is(queuePercentage).betweenExclusive(BigDecimal.ZERO, BigDecimal.ONE);
+ }
+
+ /**
+ * Convert a {@link BigInteger} into an {@link UnsignedLong} without overflowing. If the input overflows, return
+ * {@link UnsignedLong#MAX_VALUE} instead.
+ *
+ * @param value A {@link BigInteger} to convert.
+ *
+ * @return An equivalent {@code value} as an {@link UnsignedLong}, or {@link UnsignedLong#MAX_VALUE} if the input
+ * would overflow during conversion.
+ */
+ // TODO: Move to MathUtils once all v3 modules are condensed and MathUtils is accessible.
+ @VisibleForTesting
+ static UnsignedLong toUnsignedLongSafe(final BigInteger value) {
+ Objects.requireNonNull(value);
+ return UnsignedLong.valueOf(min(value, MAX_UNSIGNED_LONG));
+ }
+
+ /**
+ * Pick the smaller of the two supplied inputs.
+ *
+ * @param input1 A {@link BigInteger} to potentially choose as the min (i.e., smallest) value.
+ * @param otherInputs A potentially empty array of {@link BigInteger}'s to compare and potentially choose from.
+ *
+ * @return The smallest value of any supplied inputs, or {@code input1} if that is the only supplied input.
+ */
+ // TODO: Move to MathUtils once all v3 modules are condensed and MathUtils is accessible.
+ @VisibleForTesting
+ static BigInteger min(final BigInteger input1, final BigInteger... otherInputs) {
+ Objects.requireNonNull(input1);
+ Objects.requireNonNull(otherInputs);
+
+ return Arrays.stream(otherInputs).min(BigInteger::compareTo).orElse(input1).min(input1);
+ }
+
+ /**
+ * Pick the larger of the two supplied inputs.
+ *
+ * @param input1 A {@link BigInteger} to potentially choose as the max (i.e., largest) value.
+ * @param otherInputs A potentially empty array of {@link BigInteger}'s to compare and potentially choose from.
+ *
+ * @return The largest value of any supplied inputs, or {@code input1} if that is the only supplied input.
+ */
+ // TODO: Move to MathUtils once all v3 modules are condensed and MathUtils is accessible.
+ @VisibleForTesting
+ static BigInteger max(final BigInteger input1, final BigInteger... otherInputs) {
+ Objects.requireNonNull(input1);
+ Objects.requireNonNull(otherInputs);
+
+ return Arrays.stream(otherInputs).max(BigInteger::compareTo).orElse(input1).max(input1);
+ }
+
+ /**
+ * Divides two {@link BigDecimal} numbers and then converts the result into a rounded {@link BigInteger}.
+ *
+ * @param numerator A {@link BigInteger} numerator for purposes of division.
+ * @param denominator A {@link BigInteger} denominator for purposes of division.
+ *
+ * @return A {@link BigInteger} result.
+ */
+ @VisibleForTesting
+ static BigInteger divideToBigInteger(final BigDecimal numerator, final BigDecimal denominator) {
+ Objects.requireNonNull(numerator);
+ Objects.requireNonNull(denominator);
+ Preconditions.checkArgument(FluentCompareTo.is(denominator).greaterThan(BigDecimal.ZERO));
+ return numerator.divide(denominator, 0, RoundingMode.HALF_UP).toBigIntegerExact();
+ }
+
+ /**
+ * Divides two {@link BigInteger} numbers and then converts the result into a rounded {@link BigInteger}.
+ *
+ * @param numerator A {@link BigInteger} numerator for purposes of division.
+ * @param denominator A {@link BigInteger} denominator for purposes of division.
+ *
+ * @return A {@link BigInteger} result.
+ */
+ @VisibleForTesting
+ static BigInteger divideToBigInteger(final BigInteger numerator, final BigInteger denominator) {
+ return divideToBigInteger(new BigDecimal(numerator), new BigDecimal(denominator));
+ }
+
+ /**
+ * Multiply input1 {@link BigInteger} by input1 {@link BigDecimal} and then return the result as input1 rounded
+ * {@link BigInteger}.
+ *
+ * @param input1 The first {@link BigInteger}.
+ * @param input2 The second {@link BigInteger}.
+ *
+ * @return The multiplied amount.
+ */
+ @VisibleForTesting
+ static BigInteger multiplyToBigInteger(final BigInteger input1, final BigDecimal input2) {
+ Objects.requireNonNull(input1);
+ Objects.requireNonNull(input2);
+ return new BigDecimal(input1).multiply(input2).setScale(0, RoundingMode.HALF_UP).toBigIntegerExact();
+ }
+
+ /**
+ * Helper object that exists solely to aid fee calculation so that BigInteger/BigDecimal objects don't have to be
+ * created more than once per call, and to put data into a state that simplifies fee calculation logic.
+ */
+ @Immutable
+ public interface DecomposedFees {
+
+ BigDecimal ONE_POINT_FIVE = new BigDecimal("1.5");
+ BigInteger MAX_XRP_IN_DROPS_BIG_INT = BigInteger.valueOf(MAX_XRP_IN_DROPS);
+
+ /**
+ * Build a new instance of {@link DecomposedFees} from the supplied input.
+ *
+ * @param feeResult A {@link FeeResult} to use as input.
+ *
+ * @return A {@link DecomposedFees}.
+ */
+ static DecomposedFees builder(final FeeResult feeResult) {
+ Objects.requireNonNull(feeResult);
+
+ final BigDecimal currentQueueSize = new BigDecimal(feeResult.currentQueueSize().bigIntegerValue());
+ final BigDecimal maxQueueSize = feeResult.maxQueueSize().map(UnsignedInteger::bigIntegerValue)
+ .map(BigDecimal::new).orElse(new BigDecimal(5000)); // Arbitrary value, but should generally be present.
+ // Don't divide by 0
+ final BigDecimal queuePercentage = FluentCompareTo.is(currentQueueSize).equalTo(BigDecimal.ZERO) ? BigDecimal.ZERO
+ : currentQueueSize.divide(maxQueueSize, MathContext.DECIMAL128);
+
+ return builder(feeResult.drops(), queuePercentage);
+ }
+
+ /**
+ * Build a new instance of {@link DecomposedFees} from the supplied input.
+ *
+ * @param feeDrops A {@link FeeDrops} to use as input.
+ * @param queuePercentage A {@link BigDecimal} representing how full the transaction queue is.
+ *
+ * @return A {@link DecomposedFees}.
+ */
+ static DecomposedFees builder(final FeeDrops feeDrops, final BigDecimal queuePercentage) {
+ Objects.requireNonNull(feeDrops);
+ Objects.requireNonNull(queuePercentage);
+ Preconditions.checkArgument(FluentCompareTo.is(queuePercentage).greaterThanEqualTo(BigDecimal.ZERO));
+ Preconditions.checkArgument(FluentCompareTo.is(queuePercentage).lessThanOrEqualTo(BigDecimal.ONE));
+
+ // Min fee should be slightly larger than the indicated min.
+ final BigInteger adjustedMinimumFeeDrops = min(MAX_XRP_IN_DROPS_BIG_INT,
+ new BigDecimal(feeDrops.minimumFee().value().bigIntegerValue()).multiply(ONE_POINT_FIVE)
+ .setScale(0, RoundingMode.HALF_DOWN).toBigIntegerExact());
+
+ return ImmutableDecomposedFees.builder().adjustedMinimumFeeDrops(adjustedMinimumFeeDrops)
+ .medianFeeDrops(feeDrops.medianFee().value().bigIntegerValue())
+ .openLedgerFeeDrops(feeDrops.openLedgerFee().value().bigIntegerValue()).queuePercentage(queuePercentage)
+ .build();
+ }
+
+ /**
+ * The minimum ledger fee as found in the supplied {@link FeeDrops} that was used to construct this instance.,
+ * adjusted to be at least 50% larger than what was supplied in order to provide a buffer for fee calculations.
+ *
+ * @return A {@link BigInteger} representing the adjusted minimum fee (in drops).
+ */
+ BigInteger adjustedMinimumFeeDrops();
+
+ /**
+ * An equivalent of {@link #adjustedMinimumFeeDrops()}, but as a {@link BigDecimal}.
+ *
+ * @return A {@link BigDecimal} representing the adjusted minimum transaction fee on ledger (in drops).
+ */
+ @Derived
+ default BigDecimal adjustedMinimumFeeDropsAsBigDecimal() {
+ return new BigDecimal(adjustedMinimumFeeDrops());
+ }
+
+ /**
+ * The median ledger fee as found in the supplied {@link FeeDrops} that was used to construct this instance.
+ *
+ * @return A {@link BigInteger} representing the median transaction fee on ledger (in drops).
+ */
+ BigInteger medianFeeDrops();
+
+ /**
+ * An equivalent of {@link #medianFeeDrops()}, but as a {@link BigDecimal}.
+ *
+ * @return A {@link BigDecimal} representing the median transaction fee on ledger (in drops).
+ */
+ @Derived
+ default BigDecimal medianFeeDropsAsBigDecimal() {
+ return new BigDecimal(medianFeeDrops());
+ }
+
+ /**
+ * The open ledger fee as found in the supplied {@link FeeDrops} that was used to construct this instance.
+ *
+ * @return A {@link BigInteger} representing open ledger fee on ledger (in drops).
+ */
+ BigInteger openLedgerFeeDrops();
+
+ /**
+ * An equivalent of {@link #openLedgerFeeDrops()}, but as a {@link BigDecimal}.
+ *
+ * @return A {@link BigInteger} representing open ledger fee on ledger (in drops).
+ */
+ @Derived
+ default BigDecimal openLedgerFeeDropsAsBigDecimal() {
+ return new BigDecimal(openLedgerFeeDrops());
+ }
+
+ /**
+ * Measures the fullness of the transaction queue by representing the percent full that the queue is. For example,
+ * if the transaction queue can hold two transactions, and one is in the queue, then this value would be 50%, or
+ * 0.5.
+ *
+ * @return A {@link BigDecimal}.
+ */
+ BigDecimal queuePercentage();
+ }
+}
diff --git a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/CurrencyAmount.java b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/CurrencyAmount.java
index 585ee04b8..9d9e6e346 100644
--- a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/CurrencyAmount.java
+++ b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/CurrencyAmount.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.
@@ -31,13 +31,17 @@
*/
public interface CurrencyAmount {
+ long ONE_XRP_IN_DROPS = 1_000_000L;
+ long MAX_XRP = 100_000_000_000L; // <-- per https://xrpl.org/rippleapi-reference.html#value
+ long MAX_XRP_IN_DROPS = MAX_XRP * ONE_XRP_IN_DROPS;
+
/**
* Handle this {@link CurrencyAmount} depending on its actual polymorphic sub-type.
*
- * @param xrpCurrencyAmountHandler A {@link Consumer} that is called if this instance is of type {@link
- * XrpCurrencyAmount}.
- * @param issuedCurrencyAmountConsumer A {@link Consumer} that is called if this instance is of type {@link
- * IssuedCurrencyAmount}.
+ * @param xrpCurrencyAmountHandler A {@link Consumer} that is called if this instance is of type
+ * {@link XrpCurrencyAmount}.
+ * @param issuedCurrencyAmountConsumer A {@link Consumer} that is called if this instance is of type
+ * {@link IssuedCurrencyAmount}.
*/
default void handle(
final Consumer xrpCurrencyAmountHandler,
@@ -58,10 +62,10 @@ default void handle(
/**
* Map this {@link CurrencyAmount} to an instance of {@link R}, depending on its actualy polymorphic sub-type.
*
- * @param xrpCurrencyAmountMapper A {@link Function} that is called if this instance is of type {@link
- * XrpCurrencyAmount}.
- * @param issuedCurrencyAmountMapper A {@link Function} that is called if this instance is of type {@link
- * IssuedCurrencyAmount}.
+ * @param xrpCurrencyAmountMapper A {@link Function} that is called if this instance is of type
+ * {@link XrpCurrencyAmount}.
+ * @param issuedCurrencyAmountMapper A {@link Function} that is called if this instance is of type
+ * {@link IssuedCurrencyAmount}.
* @param The type of object to return after mapping.
*
* @return A {@link R} that is constructed by the appropriate mapper function.
diff --git a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java
index 528dbb4fa..e55fc71f3 100644
--- a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java
+++ b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.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.
@@ -95,6 +95,7 @@ public interface Transaction {
*
* @return An {@link XrpCurrencyAmount} representing the multisig fee.
*/
+ @Deprecated
static XrpCurrencyAmount computeMultiSigFee(
final XrpCurrencyAmount currentLedgerFeeDrops,
final SignerListObject signerList
@@ -232,7 +233,7 @@ default UnsignedInteger sequence() {
*
* @return An optionally-present {@link UnsignedLong}.
* @deprecated This field will be removed in favor of {@link
- * org.xrpl.xrpl4j.model.client.transactions.TransactionResult#closeDate()};
+ * org.xrpl.xrpl4j.model.client.transactions.TransactionResult#closeDate()};
*/
@JsonProperty("date")
@Deprecated
diff --git a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Wrappers.java b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Wrappers.java
index 9e57c5274..5c77a8e77 100644
--- a/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Wrappers.java
+++ b/xrpl4j-model/src/main/java/org/xrpl/xrpl4j/model/transactions/Wrappers.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.
@@ -61,7 +61,7 @@ public String toString() {
*/
@Value.Check
public void validateAddress() {
- Preconditions.checkArgument(this.value().startsWith("r"),"Invalid Address: Bad Prefix");
+ Preconditions.checkArgument(this.value().startsWith("r"), "Invalid Address: Bad Prefix");
Preconditions.checkArgument(this.value().length() >= 25 && this.value().length() <= 35,
"Classic Addresses must be (25,35) characters long inclusive.");
}
@@ -133,9 +133,30 @@ public int hashCode() {
@JsonDeserialize(as = XrpCurrencyAmount.class)
abstract static class _XrpCurrencyAmount extends Wrapper implements Serializable, CurrencyAmount {
+ /**
+ * One XRP, in drops.
+ *
+ * @deprecated Prefer {@link CurrencyAmount#ONE_XRP_IN_DROPS}.
+ */
+ @Deprecated
static final long ONE_XRP_IN_DROPS = 1_000_000L;
+
+ /**
+ * The largest XRP amount.
+ *
+ * @deprecated Prefer {@link CurrencyAmount#MAX_XRP}.
+ */
+ @Deprecated
static final long MAX_XRP = 100_000_000_000L; // <-- per https://xrpl.org/rippleapi-reference.html#value
+
+ /**
+ * The largest XRP amount, in drops.
+ *
+ * @deprecated Prefer {@link CurrencyAmount#MAX_XRP_IN_DROPS}.
+ */
+ @Deprecated
static final long MAX_XRP_IN_DROPS = MAX_XRP * ONE_XRP_IN_DROPS;
+
static final BigDecimal SMALLEST_XRP = new BigDecimal("0.000001");
static final DecimalFormat FORMATTER = new DecimalFormat("###,###");
@@ -232,7 +253,8 @@ protected void check() {
Preconditions.checkState(
FluentCompareTo.is(value()).lessThanOrEqualTo(UnsignedLong.valueOf(MAX_XRP_IN_DROPS)),
String.format(
- "XRP Amounts may not exceed %s drops (100B XRP, denominated in Drops)", FORMATTER.format(MAX_XRP_IN_DROPS))
+ "XRP Amounts may not exceed %s drops (100B XRP, denominated in Drops)", FORMATTER.format(MAX_XRP_IN_DROPS)
+ )
);
}
diff --git a/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/DecomposedFeesTest.java b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/DecomposedFeesTest.java
new file mode 100644
index 000000000..5abc345f4
--- /dev/null
+++ b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/DecomposedFeesTest.java
@@ -0,0 +1,151 @@
+package org.xrpl.xrpl4j.model.client.fees;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.mockito.Mockito.when;
+import static org.xrpl.xrpl4j.model.client.fees.FeeUtils.DecomposedFees.MAX_XRP_IN_DROPS_BIG_INT;
+import static org.xrpl.xrpl4j.model.transactions.CurrencyAmount.MAX_XRP_IN_DROPS;
+
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Optional;
+
+/**
+ * Unit tests for {@link FeeUtils.DecomposedFees}.
+ */
+public class DecomposedFeesTest {
+
+ @Mock
+ FeeDrops feeDropsMock;
+
+ @Mock
+ FeeResult feeResultMock;
+
+ @BeforeEach
+ void setup() {
+ MockitoAnnotations.openMocks(this);
+
+ when(feeResultMock.drops()).thenReturn(feeDropsMock);
+ when(feeResultMock.currentQueueSize()).thenReturn(UnsignedInteger.ZERO);
+ when(feeResultMock.maxQueueSize()).thenReturn(Optional.of(UnsignedInteger.ONE));
+
+ when(feeDropsMock.minimumFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ZERO).build());
+ when(feeDropsMock.medianFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ZERO).build());
+ when(feeDropsMock.openLedgerFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ZERO).build());
+ }
+
+ @Test
+ void buildWithZeroFees() {
+ when(feeDropsMock.minimumFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ZERO).build());
+ when(feeDropsMock.medianFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ZERO).build());
+ when(feeDropsMock.openLedgerFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ZERO).build());
+
+ FeeUtils.DecomposedFees decomposedFees = FeeUtils.DecomposedFees.builder(feeResultMock);
+
+ assertThat(decomposedFees.adjustedMinimumFeeDrops()).isEqualTo(BigInteger.ZERO);
+ assertThat(decomposedFees.adjustedMinimumFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.ZERO);
+ assertThat(decomposedFees.medianFeeDrops()).isEqualTo(BigInteger.ZERO);
+ assertThat(decomposedFees.medianFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.ZERO);
+ assertThat(decomposedFees.openLedgerFeeDrops()).isEqualTo(BigInteger.ZERO);
+ assertThat(decomposedFees.openLedgerFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.ZERO);
+ }
+
+ @Test
+ void buildWithOneFees() {
+ when(feeDropsMock.minimumFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ONE).build());
+ when(feeDropsMock.medianFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ONE).build());
+ when(feeDropsMock.openLedgerFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ONE).build());
+
+ FeeUtils.DecomposedFees decomposedFees = FeeUtils.DecomposedFees.builder(feeResultMock);
+
+ assertThat(decomposedFees.adjustedMinimumFeeDrops()).isEqualTo(BigInteger.ONE);
+ assertThat(decomposedFees.adjustedMinimumFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.ONE);
+ assertThat(decomposedFees.medianFeeDrops()).isEqualTo(BigInteger.ONE);
+ assertThat(decomposedFees.medianFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.ONE);
+ assertThat(decomposedFees.openLedgerFeeDrops()).isEqualTo(BigInteger.ONE);
+ assertThat(decomposedFees.openLedgerFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.ONE);
+ }
+
+ @Test
+ void buildWithTenFees() {
+ when(feeDropsMock.minimumFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.valueOf(10L)).build());
+ when(feeDropsMock.medianFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.valueOf(10L)).build());
+ when(feeDropsMock.openLedgerFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.valueOf(10L)).build());
+
+ FeeUtils.DecomposedFees decomposedFees = FeeUtils.DecomposedFees.builder(feeResultMock);
+
+ assertThat(decomposedFees.adjustedMinimumFeeDrops()).isEqualTo(BigInteger.valueOf(15L));
+ assertThat(decomposedFees.adjustedMinimumFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.valueOf(15L));
+ assertThat(decomposedFees.medianFeeDrops()).isEqualTo(BigInteger.valueOf(10L));
+ assertThat(decomposedFees.medianFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.valueOf(10L));
+ assertThat(decomposedFees.openLedgerFeeDrops()).isEqualTo(BigInteger.valueOf(10L));
+ assertThat(decomposedFees.openLedgerFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.valueOf(10L));
+ }
+
+ @Test
+ void buildWithMaxFees() {
+ when(feeResultMock.currentQueueSize()).thenReturn(UnsignedInteger.MAX_VALUE);
+ when(feeResultMock.maxQueueSize()).thenReturn(Optional.of(UnsignedInteger.MAX_VALUE));
+
+ final UnsignedLong maxFees = UnsignedLong.valueOf(MAX_XRP_IN_DROPS);
+ when(feeDropsMock.minimumFee()).thenReturn(
+ XrpCurrencyAmount.builder().value(maxFees).build());
+ when(feeDropsMock.medianFee()).thenReturn(
+ XrpCurrencyAmount.builder().value(maxFees).build());
+ when(feeDropsMock.openLedgerFee()).thenReturn(
+ XrpCurrencyAmount.builder().value(maxFees).build());
+
+ FeeUtils.DecomposedFees decomposedFees = FeeUtils.DecomposedFees.builder(feeResultMock);
+
+ assertThat(decomposedFees.adjustedMinimumFeeDrops()).isEqualTo(MAX_XRP_IN_DROPS_BIG_INT);
+ assertThat(decomposedFees.adjustedMinimumFeeDropsAsBigDecimal())
+ .isEqualTo(new BigDecimal(maxFees.bigIntegerValue()));
+ assertThat(decomposedFees.medianFeeDrops()).isEqualTo(MAX_XRP_IN_DROPS_BIG_INT);
+ assertThat(decomposedFees.medianFeeDropsAsBigDecimal())
+ .isEqualTo(new BigDecimal(maxFees.bigIntegerValue()));
+ assertThat(decomposedFees.openLedgerFeeDrops()).isEqualTo(MAX_XRP_IN_DROPS_BIG_INT);
+ assertThat(decomposedFees.openLedgerFeeDropsAsBigDecimal())
+ .isEqualTo(new BigDecimal(maxFees.bigIntegerValue()));
+ }
+
+ @Test
+ void buildWithEmptyMaxQueueSize() {
+ when(feeResultMock.currentQueueSize()).thenReturn(UnsignedInteger.ONE);
+ when(feeResultMock.maxQueueSize()).thenReturn(Optional.empty());
+
+ when(feeDropsMock.minimumFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ONE).build());
+ when(feeDropsMock.medianFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ONE).build());
+ when(feeDropsMock.openLedgerFee()).thenReturn(XrpCurrencyAmount.builder().value(UnsignedLong.ONE).build());
+
+ FeeUtils.DecomposedFees decomposedFees = FeeUtils.DecomposedFees.builder(feeResultMock);
+
+ assertThat(decomposedFees.adjustedMinimumFeeDrops()).isEqualTo(BigInteger.ONE);
+ assertThat(decomposedFees.adjustedMinimumFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.ONE);
+ assertThat(decomposedFees.medianFeeDrops()).isEqualTo(BigInteger.ONE);
+ assertThat(decomposedFees.medianFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.ONE);
+ assertThat(decomposedFees.openLedgerFeeDrops()).isEqualTo(BigInteger.ONE);
+ assertThat(decomposedFees.openLedgerFeeDropsAsBigDecimal()).isEqualTo(BigDecimal.ONE);
+ }
+
+ @Test
+ void buildWithNegativeQueuePercentage() {
+ when(feeResultMock.currentQueueSize()).thenReturn(UnsignedInteger.ONE);
+ when(feeResultMock.maxQueueSize()).thenReturn(Optional.empty());
+
+ Assertions.assertThrows(IllegalArgumentException.class, () -> {
+ FeeUtils.DecomposedFees.builder(feeDropsMock, BigDecimal.valueOf(-1));
+ });
+ Assertions.assertThrows(IllegalArgumentException.class, () -> {
+ FeeUtils.DecomposedFees.builder(feeDropsMock, BigDecimal.valueOf(1.1));
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/FeeUtilsTest.java b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/FeeUtilsTest.java
new file mode 100644
index 000000000..807de1f1c
--- /dev/null
+++ b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/FeeUtilsTest.java
@@ -0,0 +1,574 @@
+package org.xrpl.xrpl4j.model.client.fees;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.xrpl.xrpl4j.model.client.fees.FeeUtils.computeMultisigNetworkFees;
+import static org.xrpl.xrpl4j.model.client.fees.FeeUtils.computeNetworkFees;
+import static org.xrpl.xrpl4j.model.transactions.CurrencyAmount.MAX_XRP;
+import static org.xrpl.xrpl4j.model.transactions.CurrencyAmount.MAX_XRP_IN_DROPS;
+
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.client.common.LedgerIndex;
+import org.xrpl.xrpl4j.model.flags.Flags;
+import org.xrpl.xrpl4j.model.ledger.SignerEntry;
+import org.xrpl.xrpl4j.model.ledger.SignerEntryWrapper;
+import org.xrpl.xrpl4j.model.ledger.SignerListObject;
+import org.xrpl.xrpl4j.model.transactions.Address;
+import org.xrpl.xrpl4j.model.transactions.Hash256;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * Unit tests for {@link FeeUtils}.
+ */
+public class FeeUtilsTest {
+
+ @Test
+ public void nullInputForComputeMultiSigFee() {
+ assertThrows(
+ NullPointerException.class,
+ () -> computeMultisigNetworkFees(null, mock(SignerListObject.class))
+ );
+
+ assertThrows(
+ NullPointerException.class,
+ () -> computeMultisigNetworkFees(mock(FeeResult.class), null)
+ );
+ }
+
+ @Test
+ public void simpleComputeMultiSigFee() {
+ FeeResult feeResult = feeResultBuilder().build();
+ SignerListObject object = SignerListObject.builder()
+ .flags(Flags.SignerListFlags.UNSET)
+ .ownerNode("0000000000000000")
+ .previousTransactionId(Hash256.of("5904C0DC72C58A83AEFED2FFC5386356AA83FCA6A88C89D00646E51E687CDBE4"))
+ .previousTransactionLedgerSequence(UnsignedInteger.valueOf(16061435))
+ .addSignerEntries(
+ SignerEntryWrapper.of(
+ SignerEntry.builder()
+ .account(Address.of("rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW"))
+ .signerWeight(UnsignedInteger.valueOf(2))
+ .build()
+ ),
+ SignerEntryWrapper.of(
+ SignerEntry.builder()
+ .account(Address.of("raKEEVSGnKSD9Zyvxu4z6Pqpm4ABH8FS6n"))
+ .signerWeight(UnsignedInteger.valueOf(1))
+ .build()
+ )
+ )
+ .signerListId(UnsignedInteger.ZERO)
+ .signerQuorum(UnsignedInteger.valueOf(3))
+ .index(Hash256.of("A9C28A28B85CD533217F5C0A0C7767666B093FA58A0F2D80026FCC4CD932DDC7"))
+ .build();
+
+ assertThat(computeMultisigNetworkFees(feeResult, object).recommendedFee())
+ .isEqualTo(XrpCurrencyAmount.ofDrops(15024));
+ assertThat(computeMultisigNetworkFees(feeResult, object).feeLow())
+ .isEqualTo(XrpCurrencyAmount.ofDrops(3000));
+ assertThat(computeMultisigNetworkFees(feeResult, object).feeMedium())
+ .isEqualTo(XrpCurrencyAmount.ofDrops(15024));
+ assertThat(computeMultisigNetworkFees(feeResult, object).feeHigh())
+ .isEqualTo(XrpCurrencyAmount.ofDrops(30000));
+ }
+
+ @Test
+ public void nullInputForCalculateFeeDynamically() {
+ assertThrows(
+ NullPointerException.class,
+ () -> computeNetworkFees(null)
+ );
+ }
+
+ @Test
+ public void computeNetworkFeesForAlmostEmptyQueue() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(1))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(10000))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2653937))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(1100))
+ .status("success")
+ .build();
+
+ ComputedNetworkFees computedNetworkFees = computeNetworkFees(feeResult);
+ assertThat(computedNetworkFees.feeLow()).isEqualTo(XrpCurrencyAmount.ofDrops(1000));
+ assertThat(computedNetworkFees.feeMedium()).isEqualTo(XrpCurrencyAmount.ofDrops(5008));
+ assertThat(computedNetworkFees.feeHigh()).isEqualTo(XrpCurrencyAmount.ofDrops(10000));
+ assertThat(computedNetworkFees.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(5008));
+ }
+
+ @Test
+ public void computeNetworkFeesForModeratelyFilledQueue() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(220))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(10000))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2653937))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(1100))
+ .status("success")
+ .build();
+
+ ComputedNetworkFees networkFeeResult = computeNetworkFees(feeResult);
+ assertThat(networkFeeResult.feeLow()).isEqualTo(XrpCurrencyAmount.ofDrops(1000));
+ assertThat(networkFeeResult.feeMedium()).isEqualTo(XrpCurrencyAmount.ofDrops(10000));
+ assertThat(networkFeeResult.feeHigh()).isEqualTo(XrpCurrencyAmount.ofDrops(10000));
+ assertThat(networkFeeResult.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(10000));
+ }
+
+ @Test
+ public void computeNetworkFeesForLessThanModerateTraffic() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(100))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(10000))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2653937))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(1100))
+ .status("success")
+ .build();
+
+ ComputedNetworkFees networkFeeResult = computeNetworkFees(feeResult);
+ assertThat(networkFeeResult.feeLow()).isEqualTo(XrpCurrencyAmount.ofDrops(1000));
+ assertThat(networkFeeResult.feeMedium()).isEqualTo(XrpCurrencyAmount.ofDrops(5008));
+ assertThat(networkFeeResult.feeHigh()).isEqualTo(XrpCurrencyAmount.ofDrops(10000));
+ assertThat(networkFeeResult.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(5008));
+ }
+
+ @Test
+ public void computeNetworkFeesForCompletelyFilledQueue() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(110))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(100))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2657))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(110))
+ .status("success")
+ .build();
+
+ ComputedNetworkFees networkFeeResult = computeNetworkFees(feeResult);
+ assertThat(networkFeeResult.feeLow()).isEqualTo(XrpCurrencyAmount.ofDrops(15));
+ assertThat(networkFeeResult.feeMedium()).isEqualTo(XrpCurrencyAmount.ofDrops(225));
+ assertThat(networkFeeResult.feeHigh()).isEqualTo(XrpCurrencyAmount.ofDrops(2923));
+ assertThat(networkFeeResult.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(2923));
+ }
+
+ @Test
+ public void computeNetworkFeesForEmptyQueue() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(0))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(100))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2657))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(110))
+ .status("success")
+ .build();
+
+ ComputedNetworkFees networkFeeResult = computeNetworkFees(feeResult);
+ assertThat(networkFeeResult.feeLow()).isEqualTo(XrpCurrencyAmount.ofDrops(15));
+ assertThat(networkFeeResult.feeMedium()).isEqualTo(XrpCurrencyAmount.ofDrops(150));
+ assertThat(networkFeeResult.feeHigh()).isEqualTo(XrpCurrencyAmount.ofDrops(2923));
+ assertThat(networkFeeResult.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(15));
+ }
+
+ @Test
+ public void calculateFeeUsingXummTestValuesForLow() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(1))
+ .currentQueueSize(UnsignedInteger.valueOf(0))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(5000))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(5343))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(10))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(2000))
+ .status("success")
+ .build();
+
+ ComputedNetworkFees networkFeeResult = computeNetworkFees(feeResult);
+ assertThat(networkFeeResult.feeLow()).isEqualTo(XrpCurrencyAmount.ofDrops(15));
+ assertThat(networkFeeResult.feeMedium()).isEqualTo(XrpCurrencyAmount.ofDrops(225));
+ assertThat(networkFeeResult.feeHigh()).isEqualTo(XrpCurrencyAmount.ofDrops(5877));
+ assertThat(networkFeeResult.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(15));
+ }
+
+ @Test
+ public void calculateFeeUsingXummTestValuesForMedium() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(1))
+ .currentQueueSize(UnsignedInteger.valueOf(1924))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(5000))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(5343))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(10))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(2000))
+ .status("success")
+ .build();
+
+ ComputedNetworkFees networkFeeResult = computeNetworkFees(feeResult);
+ assertThat(networkFeeResult.feeLow()).isEqualTo(XrpCurrencyAmount.ofDrops(15));
+ assertThat(networkFeeResult.feeMedium()).isEqualTo(XrpCurrencyAmount.ofDrops(225));
+ assertThat(networkFeeResult.feeHigh()).isEqualTo(XrpCurrencyAmount.ofDrops(5877));
+ assertThat(networkFeeResult.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(225));
+ }
+
+ @Test
+ public void calculateFeeUsingXummTestValuesForHigh() {
+ FeeResult feeResult = FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(1))
+ .currentQueueSize(UnsignedInteger.valueOf(2000))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(5000))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(5343))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(10))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(2000))
+ .status("success")
+ .build();
+
+ ComputedNetworkFees networkFeeResult = computeNetworkFees(feeResult);
+ assertThat(networkFeeResult.feeLow()).isEqualTo(XrpCurrencyAmount.ofDrops(15));
+ assertThat(networkFeeResult.feeMedium()).isEqualTo(XrpCurrencyAmount.ofDrops(225));
+ assertThat(networkFeeResult.feeHigh()).isEqualTo(XrpCurrencyAmount.ofDrops(5877));
+ assertThat(networkFeeResult.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(5877));
+ }
+
+ @Test
+ void testQueueIsEmpty() {
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.queueIsEmpty(null)
+ );
+
+ assertThat(FeeUtils.queueIsEmpty(BigDecimal.valueOf(-1))).isTrue();
+ assertThat(FeeUtils.queueIsEmpty(BigDecimal.ZERO)).isTrue();
+ assertThat(FeeUtils.queueIsEmpty(BigDecimal.valueOf(0.1))).isFalse();
+ assertThat(FeeUtils.queueIsEmpty(BigDecimal.valueOf(0.4))).isFalse();
+ assertThat(FeeUtils.queueIsEmpty(BigDecimal.valueOf(0.5))).isFalse();
+ assertThat(FeeUtils.queueIsEmpty(BigDecimal.valueOf(0.6))).isFalse();
+ assertThat(FeeUtils.queueIsEmpty(BigDecimal.valueOf(0.999999))).isFalse();
+ assertThat(FeeUtils.queueIsEmpty(BigDecimal.ONE)).isFalse();
+ assertThat(FeeUtils.queueIsEmpty(BigDecimal.valueOf(2))).isFalse();
+ }
+
+ @Test
+ void testQueueIsNotEmptyAndNotFull() {
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.queueIsNotEmptyAndNotFull(null)
+ );
+
+ assertThat(FeeUtils.queueIsNotEmptyAndNotFull(BigDecimal.valueOf(-1))).isFalse();
+ assertThat(FeeUtils.queueIsNotEmptyAndNotFull(BigDecimal.ZERO)).isFalse();
+ assertThat(FeeUtils.queueIsNotEmptyAndNotFull(BigDecimal.valueOf(0.1))).isTrue();
+ assertThat(FeeUtils.queueIsNotEmptyAndNotFull(BigDecimal.valueOf(0.4))).isTrue();
+ assertThat(FeeUtils.queueIsNotEmptyAndNotFull(BigDecimal.valueOf(0.5))).isTrue();
+ assertThat(FeeUtils.queueIsNotEmptyAndNotFull(BigDecimal.valueOf(0.6))).isTrue();
+ assertThat(FeeUtils.queueIsNotEmptyAndNotFull(BigDecimal.valueOf(0.999999))).isTrue();
+ assertThat(FeeUtils.queueIsNotEmptyAndNotFull(BigDecimal.ONE)).isFalse();
+ assertThat(FeeUtils.queueIsNotEmptyAndNotFull(BigDecimal.valueOf(2))).isFalse();
+ }
+
+ @Test
+ void testToUnsignedLongSafe() {
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.toUnsignedLongSafe(null)
+ );
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> FeeUtils.toUnsignedLongSafe(BigInteger.valueOf(-1))
+ );
+
+ assertThat(FeeUtils.toUnsignedLongSafe(BigInteger.ZERO)).isEqualTo(UnsignedLong.ZERO);
+ assertThat(FeeUtils.toUnsignedLongSafe(BigInteger.ONE)).isEqualTo(UnsignedLong.ONE);
+ assertThat(FeeUtils.toUnsignedLongSafe(BigInteger.valueOf(MAX_XRP))).isEqualTo(UnsignedLong.valueOf(MAX_XRP));
+ assertThat(FeeUtils.toUnsignedLongSafe(BigInteger.valueOf(MAX_XRP_IN_DROPS)))
+ .isEqualTo(UnsignedLong.valueOf(MAX_XRP_IN_DROPS));
+ assertThat(FeeUtils.toUnsignedLongSafe(UnsignedLong.MAX_VALUE.bigIntegerValue())).isEqualTo(UnsignedLong.MAX_VALUE);
+ assertThat(FeeUtils.toUnsignedLongSafe(UnsignedLong.MAX_VALUE.bigIntegerValue().add(BigInteger.ONE)))
+ .isEqualTo(UnsignedLong.MAX_VALUE);
+ }
+
+ @Test
+ void testMin() {
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.min(null)
+ );
+
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.min(BigInteger.ZERO, null)
+ );
+
+ assertThat(FeeUtils.min(BigInteger.valueOf(-1), BigInteger.ZERO)).isEqualTo(BigInteger.valueOf(-1));
+ assertThat(FeeUtils.min(BigInteger.ZERO, BigInteger.ZERO)).isEqualTo(BigInteger.ZERO);
+ assertThat(FeeUtils.min(BigInteger.ZERO, BigInteger.ONE)).isEqualTo(BigInteger.ZERO);
+ assertThat(FeeUtils.min(BigInteger.ONE, BigInteger.ZERO)).isEqualTo(BigInteger.ZERO);
+ assertThat(FeeUtils.min(BigInteger.ONE, BigInteger.ONE)).isEqualTo(BigInteger.ONE);
+ assertThat(FeeUtils.min(BigInteger.ONE)).isEqualTo(BigInteger.ONE);
+ assertThat(FeeUtils.min(BigInteger.ZERO, BigInteger.valueOf(MAX_XRP_IN_DROPS))).isEqualTo(BigInteger.ZERO);
+ assertThat(FeeUtils.min(BigInteger.valueOf(MAX_XRP_IN_DROPS), BigInteger.ONE)).isEqualTo(BigInteger.ONE);
+ }
+
+ @Test
+ void testMax() {
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.max(null)
+ );
+
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.max(BigInteger.ZERO, null)
+ );
+
+ assertThat(FeeUtils.max(BigInteger.valueOf(-1), BigInteger.ZERO)).isEqualTo(BigInteger.ZERO);
+ assertThat(FeeUtils.max(BigInteger.ZERO, BigInteger.ZERO)).isEqualTo(BigInteger.ZERO);
+ assertThat(FeeUtils.max(BigInteger.ZERO, BigInteger.ONE)).isEqualTo(BigInteger.ONE);
+ assertThat(FeeUtils.max(BigInteger.ONE, BigInteger.ZERO)).isEqualTo(BigInteger.ONE);
+ assertThat(FeeUtils.max(BigInteger.ONE, BigInteger.ONE)).isEqualTo(BigInteger.ONE);
+ assertThat(FeeUtils.max(BigInteger.ONE)).isEqualTo(BigInteger.ONE);
+ assertThat(FeeUtils.max(BigInteger.ZERO, BigInteger.valueOf(MAX_XRP_IN_DROPS)))
+ .isEqualTo(BigInteger.valueOf(MAX_XRP_IN_DROPS));
+ assertThat(FeeUtils.max(BigInteger.valueOf(MAX_XRP_IN_DROPS), BigInteger.ONE))
+ .isEqualTo(BigInteger.valueOf(MAX_XRP_IN_DROPS));
+ }
+
+ @Test
+ void testDivideBigDecimalsToBigInteger() {
+ final BigDecimal nullBigDecimal = null;
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.divideToBigInteger(nullBigDecimal, BigDecimal.ONE)
+ );
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.divideToBigInteger(BigDecimal.ONE, nullBigDecimal)
+ );
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> FeeUtils.divideToBigInteger(BigDecimal.ONE, BigDecimal.valueOf(-1))
+ );
+
+ assertThat(FeeUtils.divideToBigInteger(BigDecimal.valueOf(-1), BigDecimal.ONE)).isEqualTo(BigInteger.valueOf(-1));
+ assertThat(FeeUtils.divideToBigInteger(BigDecimal.ONE, BigDecimal.valueOf(2))).isEqualTo(BigInteger.ONE);
+ assertThat(FeeUtils.divideToBigInteger(BigDecimal.ONE, BigDecimal.valueOf(4))).isEqualTo(BigInteger.ZERO);
+ assertThat(FeeUtils.divideToBigInteger(BigDecimal.ONE, BigDecimal.TEN)).isEqualTo(BigInteger.ZERO);
+ assertThat(FeeUtils.divideToBigInteger(BigDecimal.TEN, BigDecimal.valueOf(2))).isEqualTo(BigInteger.valueOf(5));
+ assertThat(FeeUtils.divideToBigInteger(new BigDecimal(UnsignedLong.MAX_VALUE.bigIntegerValue()), BigDecimal.ONE))
+ .isEqualTo(UnsignedLong.MAX_VALUE.bigIntegerValue());
+ assertThat(FeeUtils.divideToBigInteger(
+ new BigDecimal(UnsignedLong.MAX_VALUE.bigIntegerValue()),
+ new BigDecimal(UnsignedLong.MAX_VALUE.bigIntegerValue()))
+ ).isEqualTo(BigInteger.ONE);
+ }
+
+ @Test
+ void testDivideBigIntegersToBigInteger() {
+ final BigInteger nullBigInteger = null;
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.divideToBigInteger(nullBigInteger, BigInteger.ONE)
+ );
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.divideToBigInteger(BigInteger.ONE, nullBigInteger)
+ );
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> FeeUtils.divideToBigInteger(BigInteger.ONE, BigInteger.valueOf(-1))
+ );
+
+ assertThat(FeeUtils.divideToBigInteger(BigInteger.valueOf(-1), BigInteger.ONE)).isEqualTo(BigInteger.valueOf(-1));
+ assertThat(FeeUtils.divideToBigInteger(BigInteger.ONE, BigInteger.valueOf(2))).isEqualTo(BigInteger.ONE);
+ assertThat(FeeUtils.divideToBigInteger(BigInteger.ONE, BigInteger.valueOf(4))).isEqualTo(BigInteger.ZERO);
+ assertThat(FeeUtils.divideToBigInteger(BigInteger.ONE, BigInteger.TEN)).isEqualTo(BigInteger.ZERO);
+ assertThat(FeeUtils.divideToBigInteger(BigInteger.TEN, BigInteger.valueOf(2))).isEqualTo(BigInteger.valueOf(5));
+ assertThat(FeeUtils.divideToBigInteger(UnsignedLong.MAX_VALUE.bigIntegerValue(), BigInteger.ONE))
+ .isEqualTo(UnsignedLong.MAX_VALUE.bigIntegerValue());
+ assertThat(FeeUtils.divideToBigInteger(
+ UnsignedLong.MAX_VALUE.bigIntegerValue(),
+ UnsignedLong.MAX_VALUE.bigIntegerValue())
+ ).isEqualTo(BigInteger.ONE);
+ }
+
+ @Test
+ void testMultiplyToBigInteger() {
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.multiplyToBigInteger(null, BigDecimal.ONE)
+ );
+ assertThrows(
+ NullPointerException.class,
+ () -> FeeUtils.multiplyToBigInteger(BigInteger.ONE, null)
+ );
+
+ assertThat(FeeUtils.multiplyToBigInteger(BigInteger.valueOf(-1), BigDecimal.ONE)).isEqualTo(BigInteger.valueOf(-1));
+ assertThat(FeeUtils.multiplyToBigInteger(BigInteger.ONE, BigDecimal.valueOf(2))).isEqualTo(BigInteger.valueOf(2));
+ assertThat(FeeUtils.multiplyToBigInteger(BigInteger.ONE, BigDecimal.valueOf(4))).isEqualTo(BigInteger.valueOf(4));
+ assertThat(FeeUtils.multiplyToBigInteger(BigInteger.ONE, BigDecimal.TEN)).isEqualTo(BigInteger.TEN);
+ assertThat(FeeUtils.multiplyToBigInteger(BigInteger.TEN, BigDecimal.valueOf(2))).isEqualTo(BigInteger.valueOf(20));
+ assertThat(FeeUtils.multiplyToBigInteger(UnsignedLong.MAX_VALUE.bigIntegerValue(), BigDecimal.ONE))
+ .isEqualTo(UnsignedLong.MAX_VALUE.bigIntegerValue());
+ assertThat(FeeUtils.multiplyToBigInteger(
+ UnsignedLong.MAX_VALUE.bigIntegerValue(),
+ new BigDecimal(UnsignedLong.MAX_VALUE.bigIntegerValue())
+ )).isEqualTo(new BigInteger("340282366920938463426481119284349108225"));
+ }
+
+ private ImmutableFeeResult.Builder feeResultBuilder() {
+ return FeeResult.builder()
+ .currentLedgerSize(UnsignedInteger.valueOf(56))
+ .currentQueueSize(UnsignedInteger.valueOf(1))
+ .drops(
+ FeeDrops.builder()
+ .baseFee(XrpCurrencyAmount.ofDrops(10))
+ .medianFee(XrpCurrencyAmount.ofDrops(10000))
+ .minimumFee(XrpCurrencyAmount.ofDrops(10))
+ .openLedgerFee(XrpCurrencyAmount.ofDrops(2653937))
+ .build()
+ )
+ .expectedLedgerSize(UnsignedInteger.valueOf(55))
+ .ledgerCurrentIndex(LedgerIndex.of(UnsignedInteger.valueOf(26575101)))
+ .levels(
+ FeeLevels.builder()
+ .medianLevel(XrpCurrencyAmount.ofDrops(256000))
+ .minimumLevel(XrpCurrencyAmount.ofDrops(256))
+ .openLedgerLevel(XrpCurrencyAmount.ofDrops(67940792))
+ .referenceLevel(XrpCurrencyAmount.ofDrops(256))
+ .build()
+ )
+ .maxQueueSize(UnsignedInteger.valueOf(1100))
+ .status("success");
+ }
+}
diff --git a/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/NetworkFeeResultTests.java b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/NetworkFeeResultTests.java
new file mode 100644
index 000000000..61ab19d88
--- /dev/null
+++ b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/client/fees/NetworkFeeResultTests.java
@@ -0,0 +1,78 @@
+package org.xrpl.xrpl4j.model.client.fees;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import org.junit.jupiter.api.Test;
+import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
+
+import java.math.BigDecimal;
+
+/**
+ * Unit tests for {@link ComputedNetworkFees}.
+ */
+class NetworkFeeResultTests {
+
+ @Test
+ void feeOptionsLow() {
+ ComputedNetworkFees feeOptions = ComputedNetworkFees.builder()
+ .feeLow(XrpCurrencyAmount.ofDrops(1L))
+ .feeMedium(XrpCurrencyAmount.ofDrops(2L))
+ .feeHigh(XrpCurrencyAmount.ofDrops(100L))
+ .queuePercentage(BigDecimal.valueOf(-1))
+ .build();
+
+ assertThat(feeOptions.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(1L));
+ assertThat(feeOptions.isTranactionQueueFull()).isFalse();
+ assertThat(feeOptions.isTransactionQueueEmpty()).isTrue();
+
+ feeOptions = ComputedNetworkFees.builder()
+ .feeLow(XrpCurrencyAmount.ofDrops(1L))
+ .feeMedium(XrpCurrencyAmount.ofDrops(2L))
+ .feeHigh(XrpCurrencyAmount.ofDrops(100L))
+ .queuePercentage(BigDecimal.ZERO)
+ .build();
+
+ assertThat(feeOptions.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(1L));
+ assertThat(feeOptions.isTranactionQueueFull()).isFalse();
+ assertThat(feeOptions.isTransactionQueueEmpty()).isTrue();
+ }
+
+ @Test
+ void feeOptionsMedium() {
+ ComputedNetworkFees feeOptions = ComputedNetworkFees.builder()
+ .feeLow(XrpCurrencyAmount.ofDrops(1L))
+ .feeMedium(XrpCurrencyAmount.ofDrops(2L))
+ .feeHigh(XrpCurrencyAmount.ofDrops(100L))
+ .queuePercentage(BigDecimal.valueOf(0.5))
+ .build();
+
+ assertThat(feeOptions.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(2L));
+ assertThat(feeOptions.isTranactionQueueFull()).isFalse();
+ assertThat(feeOptions.isTransactionQueueEmpty()).isFalse();
+ }
+
+ @Test
+ void isTranactionQueueHigh() {
+ ComputedNetworkFees feeOptions = ComputedNetworkFees.builder()
+ .feeLow(XrpCurrencyAmount.ofDrops(1L))
+ .feeMedium(XrpCurrencyAmount.ofDrops(2L))
+ .feeHigh(XrpCurrencyAmount.ofDrops(100L))
+ .queuePercentage(BigDecimal.ONE)
+ .build();
+
+ assertThat(feeOptions.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(100L));
+ assertThat(feeOptions.isTranactionQueueFull()).isTrue();
+ assertThat(feeOptions.isTransactionQueueEmpty()).isFalse();
+
+ feeOptions = ComputedNetworkFees.builder()
+ .feeLow(XrpCurrencyAmount.ofDrops(1L))
+ .feeMedium(XrpCurrencyAmount.ofDrops(2L))
+ .feeHigh(XrpCurrencyAmount.ofDrops(100L))
+ .queuePercentage(BigDecimal.valueOf(1.1))
+ .build();
+
+ assertThat(feeOptions.recommendedFee()).isEqualTo(XrpCurrencyAmount.ofDrops(100L));
+ assertThat(feeOptions.isTranactionQueueFull()).isTrue();
+ assertThat(feeOptions.isTransactionQueueEmpty()).isFalse();
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/transactions/CurrencyAmountTest.java b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/transactions/CurrencyAmountTest.java
index 9e79ca818..f7129de5a 100644
--- a/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/transactions/CurrencyAmountTest.java
+++ b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/transactions/CurrencyAmountTest.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.
@@ -133,4 +133,11 @@ public void mapIssuance() {
issuedCurrencyAmount.map(($) -> new Object(), null)
);
}
+
+ @Test
+ void testConstants() {
+ assertThat(CurrencyAmount.ONE_XRP_IN_DROPS).isEqualTo(1_000_000L);
+ assertThat(CurrencyAmount.MAX_XRP).isEqualTo(100_000_000_000L);
+ assertThat(CurrencyAmount.MAX_XRP_IN_DROPS).isEqualTo(100_000_000_000_000_000L);
+ }
}
diff --git a/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/transactions/EscrowFinishTest.java b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/transactions/EscrowFinishTest.java
index 0cef3cd53..3d241145b 100644
--- a/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/transactions/EscrowFinishTest.java
+++ b/xrpl4j-model/src/test/java/org/xrpl/xrpl4j/model/transactions/EscrowFinishTest.java
@@ -90,7 +90,7 @@ public void testNormalizeWithNoFulfillmentAndCondition() {
}
@Test
- public void testNormalizeWithFulfillmentAndConditionButLowFee() {
+ public void testNormalizeWithFulfillmentAndConditionButFeeLow() {
// We expect the
Fulfillment fulfillment = PreimageSha256Fulfillment.from("ssh".getBytes());
From e9aa7c491eb2d8589c207951a25a07518fe24d71 Mon Sep 17 00:00:00 2001
From: David Fuelling <323659+sappenin@users.noreply.github.com>
Date: Thu, 6 Oct 2022 18:31:46 -0600
Subject: [PATCH 11/12] Fix IT to account for broken clio paging (#302)
---
.../xrpl4j/tests/AccountTransactionsIT.java | 29 ++++++++++++-------
.../tests/v3/AccountTransactionsIT.java | 22 ++++++++++----
2 files changed, 35 insertions(+), 16 deletions(-)
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AccountTransactionsIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AccountTransactionsIT.java
index 56d038fff..972f454df 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AccountTransactionsIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AccountTransactionsIT.java
@@ -24,6 +24,7 @@
import static org.awaitility.Awaitility.given;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.oneOf;
import com.google.common.primitives.UnsignedInteger;
import org.junit.jupiter.api.Test;
@@ -58,20 +59,20 @@ public class AccountTransactionsIT {
public void listTransactionsDefaultWithPagination() throws JsonRpcClientErrorException {
AccountTransactionsResult results = mainnetClient.accountTransactions(MAINNET_ADDRESS);
- assertThat(results.transactions()).hasSize(200);
+ // The default value for reporting mode is 200; but clio it's 50. However, the important things to test here is
+ // that a marker exists, so we only assert on that value.
assertThat(results.marker()).isNotEmpty();
}
@Test
@Timeout(30)
public void listTransactionsPagination() throws JsonRpcClientErrorException {
- final int expectedTransactions = 284;
+ final int expectedTransactions = 748;
// known ledger index range for this account that is known to have exactly 748 transactions
LedgerIndexBound minLedger = LedgerIndexBound.of(61400000);
- LedgerIndexBound maxLedger = LedgerIndexBound.of(61437000);
+ LedgerIndexBound maxLedger = LedgerIndexBound.of(61487000);
AccountTransactionsResult results = mainnetClient.accountTransactions(
- AccountTransactionsRequestParams
- .builder(minLedger, maxLedger)
+ AccountTransactionsRequestParams.builder(minLedger, maxLedger)
.account(MAINNET_ADDRESS)
.build()
);
@@ -79,20 +80,26 @@ public void listTransactionsPagination() throws JsonRpcClientErrorException {
assertThat(results.marker()).isNotEmpty();
int transactionsFound = results.transactions().size();
- int pages = 1;
- while (results.marker().isPresent()) {
- results = mainnetClient.accountTransactions(AccountTransactionsRequestParams
- .builder(minLedger, maxLedger)
+ int pages = 0;
+ while (results.marker().isPresent() &&
+ // Needed because clio is broken. See https://github.com/XRPLF/clio/issues/195#issuecomment-1247412892
+ results.transactions().size() > 0
+ ) {
+ results = mainnetClient.accountTransactions(AccountTransactionsRequestParams.builder(minLedger, maxLedger)
.account(MAINNET_ADDRESS)
+ .limit(UnsignedInteger.valueOf(200L))
.marker(results.marker().get())
.build());
- assertThat(results.transactions()).isNotEmpty();
transactionsFound += results.transactions().size();
pages++;
+ logger.info("Retrieved {} ledgers (marker={} page={})",
+ transactionsFound,
+ results.marker().map($ -> $.value()).orElseGet(() -> "n/a"),
+ pages
+ );
}
assertThat(transactionsFound).isEqualTo(expectedTransactions);
- assertThat(pages).isEqualTo(2);
}
@Test
diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/AccountTransactionsIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/AccountTransactionsIT.java
index a93eab75e..e58c2a538 100644
--- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/AccountTransactionsIT.java
+++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/v3/AccountTransactionsIT.java
@@ -9,6 +9,8 @@
import org.awaitility.Durations;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
import org.xrpl.xrpl4j.client.XrplClient;
import org.xrpl.xrpl4j.model.client.accounts.AccountTransactionsRequestParams;
@@ -29,6 +31,8 @@
*/
public class AccountTransactionsIT {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
// an arbitrary address on xrpl mainnet that has a decent amount of transaction history
public static final Address MAINNET_ADDRESS = Address.of("r9m6MwViR4GnUNqoGXGa8eroBrZ9FAPHFS");
@@ -38,7 +42,8 @@ public class AccountTransactionsIT {
public void listTransactionsDefaultWithPagination() throws JsonRpcClientErrorException {
AccountTransactionsResult results = mainnetClient.accountTransactions(MAINNET_ADDRESS);
- assertThat(results.transactions()).hasSize(200);
+ // The default value for reporting mode is 200; but clio it's 50. However, the important things to test here is
+ // that a marker exists, so we only assert on that value.
assertThat(results.marker()).isNotEmpty();
}
@@ -58,19 +63,26 @@ public void listTransactionsPagination() throws JsonRpcClientErrorException {
assertThat(results.marker()).isNotEmpty();
int transactionsFound = results.transactions().size();
- int pages = 1;
- while (results.marker().isPresent()) {
+ int pages = 0;
+ while (results.marker().isPresent() &&
+ // Needed because clio is broken. See https://github.com/XRPLF/clio/issues/195#issuecomment-1247412892
+ results.transactions().size() > 0
+ ) {
results = mainnetClient.accountTransactions(AccountTransactionsRequestParams.builder(minLedger, maxLedger)
.account(MAINNET_ADDRESS)
+ .limit(UnsignedInteger.valueOf(200L))
.marker(results.marker().get())
.build());
- assertThat(results.transactions()).isNotEmpty();
transactionsFound += results.transactions().size();
pages++;
+ logger.info("Retrieved {} ledgers (marker={} page={})",
+ transactionsFound,
+ results.marker().map($ -> $.value()).orElseGet(() -> "n/a"),
+ pages
+ );
}
assertThat(transactionsFound).isEqualTo(expectedTransactions);
- assertThat(pages).isEqualTo(4);
}
@Test
From 3a48818652abaf7a904d66b7f4a142425d99d5fb Mon Sep 17 00:00:00 2001
From: Mukul Jangid <49061120+mukulljangid@users.noreply.github.com>
Date: Fri, 7 Oct 2022 11:26:55 -0400
Subject: [PATCH 12/12] add serializer and deserializer for `Signature` (#305)
* add serializer and deserializer for `Signature`
* WrappedSignature example interface and test
* fix checkstyle
* add `as = ImmutableSignature.class` back
Co-authored-by: David Fuelling <323659+sappenin@users.noreply.github.com>
---
.../xrpl4j/crypto/core/signing/Signature.java | 4 +-
.../core/signing/SignatureDeserializer.java | 22 +++++++++++
.../core/signing/SignatureSerializer.java | 17 ++++++++
.../UnsignedByteArrayDeserializer.java | 2 +-
.../crypto/core/signing/SignatureTest.java | 39 ++++++++++++++++++-
5 files changed, 80 insertions(+), 4 deletions(-)
create mode 100644 xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureDeserializer.java
create mode 100644 xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureSerializer.java
diff --git a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/Signature.java b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/Signature.java
index 40054813b..62e7e3d9f 100644
--- a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/Signature.java
+++ b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/Signature.java
@@ -12,8 +12,8 @@
* Represents a digital signature for a transaction that can be submitted to the XRP Ledger.
*/
@Value.Immutable
-@JsonSerialize(as = ImmutableSignature.class)
-@JsonDeserialize(as = ImmutableSignature.class)
+@JsonSerialize(as = ImmutableSignature.class, using = SignatureSerializer.class)
+@JsonDeserialize(as = ImmutableSignature.class, using = SignatureDeserializer.class)
public interface Signature {
/**
diff --git a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureDeserializer.java b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureDeserializer.java
new file mode 100644
index 000000000..27d47611d
--- /dev/null
+++ b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureDeserializer.java
@@ -0,0 +1,22 @@
+package org.xrpl.xrpl4j.crypto.core.signing;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import org.xrpl.xrpl4j.codec.addresses.UnsignedByteArray;
+
+import java.io.IOException;
+
+/**
+ * Deserializes signature string value to an object of type {@link Signature}.
+ */
+class SignatureDeserializer extends JsonDeserializer {
+
+ @Override
+ public Signature deserialize(JsonParser jsonParser, DeserializationContext ctxt)
+ throws IOException {
+ JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+ return Signature.builder().value(UnsignedByteArray.fromHex(node.asText())).build();
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureSerializer.java b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureSerializer.java
new file mode 100644
index 000000000..ba6521023
--- /dev/null
+++ b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureSerializer.java
@@ -0,0 +1,17 @@
+package org.xrpl.xrpl4j.crypto.core.signing;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson serializer for {@link Signature}es.
+ */
+class SignatureSerializer extends JsonSerializer {
+ @Override
+ public void serialize(Signature signature, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(signature.base16Value());
+ }
+}
\ No newline at end of file
diff --git a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/UnsignedByteArrayDeserializer.java b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/UnsignedByteArrayDeserializer.java
index 4f33cb239..35704dcad 100644
--- a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/UnsignedByteArrayDeserializer.java
+++ b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/main/java/org/xrpl/xrpl4j/crypto/core/signing/UnsignedByteArrayDeserializer.java
@@ -8,7 +8,7 @@
import java.io.IOException;
/**
- * A FasterXML serializer for {@link UnsignedByteArray}.
+ * A FasterXML deserializer for {@link UnsignedByteArray}.
*
* @deprecated This class will go away once {@link UnsignedByteArray} is moved into the core module.
*/
diff --git a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/test/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureTest.java b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/test/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureTest.java
index ae1b316b3..6d50d2f22 100644
--- a/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/test/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureTest.java
+++ b/xrpl4j-crypto-parent/xrpl4j-crypto-core/src/test/java/org/xrpl/xrpl4j/crypto/core/signing/SignatureTest.java
@@ -4,7 +4,11 @@
import static org.hamcrest.Matchers.is;
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.jayway.jsonassert.JsonAssert;
+import org.immutables.value.Value;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.xrpl.xrpl4j.codec.addresses.UnsignedByteArray;
@@ -46,7 +50,8 @@ void hexValue() {
@Test
void jsonSerializeAndDeserialize() throws JsonProcessingException {
String json = ObjectMapperFactory.create().writeValueAsString(signature);
- JsonAssert.with(json).assertThat("$.value", is(HEX_32_BYTES));
+ JsonAssert.with(json).assertThat("$", is(HEX_32_BYTES));
+ assertThat(json).isEqualTo("\"" + HEX_32_BYTES + "\"");
Signature actual = ObjectMapperFactory.create().readValue(json, Signature.class);
assertThat(actual).isEqualTo(signature);
@@ -61,4 +66,36 @@ void of() {
void fromBase16() {
assertThat(Signature.fromBase16(HEX_32_BYTES)).isEqualTo(signature);
}
+
+ @Test
+ void serializeSignature() throws JsonProcessingException {
+
+ ObjectMapper objectMapper = ObjectMapperFactory.create();
+
+ WrappedSignature wrappedSignature = WrappedSignature.builder()
+ .signature(signature)
+ .build();
+ String serializedWrappedSignature = objectMapper.writeValueAsString(wrappedSignature);
+
+ String serialized = "{\"signature\":\"" + HEX_32_BYTES + "\"}";
+ assertThat(serializedWrappedSignature).isEqualTo(serialized);
+
+ WrappedSignature deserializedWrappedSignature = objectMapper.readValue(
+ serializedWrappedSignature, WrappedSignature.class
+ );
+ assertThat(deserializedWrappedSignature).isEqualTo(wrappedSignature);
+
+ }
+
+ @Value.Immutable
+ @JsonSerialize(as = ImmutableWrappedSignature.class)
+ @JsonDeserialize(as = ImmutableWrappedSignature.class)
+ interface WrappedSignature {
+
+ static ImmutableWrappedSignature.Builder builder() {
+ return ImmutableWrappedSignature.builder();
+ }
+
+ Signature signature();
+ }
}
\ No newline at end of file