From eabbafeb8db092fff845b7f3a5c86a348b14e57c Mon Sep 17 00:00:00 2001 From: nkramer44 Date: Tue, 6 Feb 2024 13:08:34 -0500 Subject: [PATCH 1/3] Update README for v3.3.0 (#523) * Update README.md --- README.md | 2 +- xrpl4j-bom/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 60c613d2d..ac0819197 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ current [BOM](https://howtodoinjava.com/maven/maven-bom-bill-of-materials-depend org.xrpl xrpl4j-bom - 3.2.1 + 3.3.0 pom import diff --git a/xrpl4j-bom/README.md b/xrpl4j-bom/README.md index 7d0024a57..e91fb86eb 100644 --- a/xrpl4j-bom/README.md +++ b/xrpl4j-bom/README.md @@ -20,7 +20,7 @@ POM file. For example: org.xrpl.xrpl4j xrpl4j-bom - 3.2.1 + 3.3.0 pom import From 2a68c4ad9388c5a9fa6b0f9146c020763aea4795 Mon Sep 17 00:00:00 2001 From: David Fuelling Date: Mon, 10 Jun 2024 10:57:47 -0600 Subject: [PATCH 2/3] Fix failing AMM IT (#536) * Reduce default amount of XRP in ITs to conform to new 100 XRP faucet policies. * Update ammendments * Update rippled container to v2.2 --- .../test/java/org/xrpl/xrpl4j/tests/AmmIT.java | 12 ++++++------ .../tests/environment/RippledContainer.java | 16 +++++++--------- .../src/test/resources/rippled/rippled.cfg | 15 ++++++++++++++- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AmmIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AmmIT.java index b908e9287..8a6799491 100644 --- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AmmIT.java +++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AmmIT.java @@ -144,8 +144,8 @@ void depositAndVoteOnTradingFee() throws JsonRpcClientErrorException, JsonProces TradingFee expectedTradingFee = TradingFee.ofPercent( issuerLpTokenBalance.multiply(amm.amm().tradingFee().bigDecimalValue()).add( traderLpTokenBalance.multiply(newTradingFee.bigDecimalValue()) - ).divide(issuerLpTokenBalance.add(traderLpTokenBalance), RoundingMode.FLOOR) - .setScale(3, RoundingMode.FLOOR) + ).divide(issuerLpTokenBalance.add(traderLpTokenBalance), RoundingMode.HALF_UP) + .setScale(3, RoundingMode.HALF_UP) ); AmmInfoResult ammAfterVote = getAmmInfo(issuerKeyPair); @@ -255,7 +255,7 @@ void depositAndWithdraw() throws JsonRpcClientErrorException, JsonProcessingExce .build() ) .asset(Issue.XRP) - .amount(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(90))) + .amount(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(9))) .flags(AmmWithdrawFlags.SINGLE_ASSET) .build(); @@ -296,7 +296,7 @@ private AccountInfoResult depositXrp( SignatureService signatureService, FeeResult feeResult ) throws JsonRpcClientErrorException, JsonProcessingException { - XrpCurrencyAmount depositAmount = XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(100)); + XrpCurrencyAmount depositAmount = XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(10)); AmmDeposit deposit = AmmDeposit.builder() .account(traderAccount.accountData().account()) .asset2( @@ -373,10 +373,10 @@ private AmmInfoResult createAmm( IssuedCurrencyAmount.builder() .issuer(issuerKeyPair.publicKey().deriveAddress()) .currency(xrpl4jCoin) - .value("25") + .value("2.5") .build() ) - .amount2(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(100))) + .amount2(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(10))) .tradingFee(TradingFee.ofPercent(BigDecimal.ONE)) .lastLedgerSequence(issuerAccount.ledgerIndexSafe().plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue()) .signingPublicKey(issuerKeyPair.publicKey()) diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/environment/RippledContainer.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/environment/RippledContainer.java index 8ed24e93a..feebbac3d 100644 --- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/environment/RippledContainer.java +++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/environment/RippledContainer.java @@ -61,7 +61,7 @@ public class RippledContainer { LOGGER.warn("Ledger accept failed", e); } }; - private final GenericContainer rippledContainer; + private final GenericContainer rippledContainer; private final ScheduledExecutorService ledgerAcceptor; private boolean started; @@ -69,7 +69,7 @@ public class RippledContainer { * No-args constructor. */ public RippledContainer() { - rippledContainer = new GenericContainer("rippleci/rippled:2.0.0-b4") + rippledContainer = new GenericContainer<>("rippleci/rippled:2.2.0-rc3") .withCreateContainerCmdModifier((Consumer) (cmd) -> cmd.withEntrypoint("/opt/ripple/bin/rippled")) .withCommand("-a --start --conf /config/rippled.cfg") @@ -92,8 +92,6 @@ public static KeyPair getMasterKeyPair() { /** * Starts container with default interval (1s) for closing ledgers. - * - * @return */ public RippledContainer start() { return this.start(1000); @@ -102,9 +100,9 @@ public RippledContainer start() { /** * Start contain with given interval for closing ledgers. * - * @param acceptIntervalMillis + * @param acceptIntervalMillis The number of milliseconds before each accept call to close the ledger. * - * @return + * @return A {@link RippledContainer}. */ public RippledContainer start(int acceptIntervalMillis) { if (started) { @@ -166,7 +164,7 @@ private void assertContainerStarted() { /** * Provides an instance of an {@link XrplAdminClient} that will connect to the rippled container. * - * @return + * @return A {@link XrplAdminClient}. */ public XrplAdminClient getXrplAdminClient() { return new XrplAdminClient(this.getBaseUri()); @@ -175,13 +173,13 @@ public XrplAdminClient getXrplAdminClient() { /** * Provides an instance of an {@link XrplClient} that will connect to the rippled container. * - * @return + * @return A {@link XrplAdminClient}. */ public XrplClient getXrplClient() { return new XrplClient(this.getBaseUri()); } - private static HttpUrl getBaseUri(GenericContainer rippledContainer) { + private static HttpUrl getBaseUri(GenericContainer rippledContainer) { return HttpUrl.parse("http://" + rippledContainer.getHost() + ":" + rippledContainer.getMappedPort(5005) + "/"); } diff --git a/xrpl4j-integration-tests/src/test/resources/rippled/rippled.cfg b/xrpl4j-integration-tests/src/test/resources/rippled/rippled.cfg index 8f909bae9..43c99131c 100644 --- a/xrpl4j-integration-tests/src/test/resources/rippled/rippled.cfg +++ b/xrpl4j-integration-tests/src/test/resources/rippled/rippled.cfg @@ -203,4 +203,17 @@ fixReducedOffersV1 fixNFTokenRemint # 2.0.0 Amendments XChainBridge -DID \ No newline at end of file +DID +fixFillOrKill +fixDisallowIncomingV1 +# 2.1.0 Amendments +fixNFTokenReserve +fixInnerObjTemplate +# 2.1.1 Amendments +fixAMMOverflowOffer +# TBD Version +fixPreviousTxnID +fixAMMv1_1 +fixEmptyDID +fixXChainRewardRounding +PriceOracle \ No newline at end of file From 55975e15da400fd246585ee60971fcb2b312f1a0 Mon Sep 17 00:00:00 2001 From: nkramer44 Date: Tue, 11 Jun 2024 11:20:23 -0400 Subject: [PATCH 3/3] Fix 529: Make all AMM transaction IssuedCurrencyAmount fields CurrencyAmounts (#534) make all AMM transaction IssuedCurrencyAmount fields CurrencyAmounts Co-authored-by: David Fuelling --- .../xrpl4j/model/transactions/AmmBid.java | 24 +++++-- .../xrpl4j/model/transactions/AmmDeposit.java | 12 +++- .../model/transactions/AmmWithdraw.java | 10 ++- .../xrpl4j/model/transactions/AmmBidTest.java | 63 +++++++++++++++++++ .../model/transactions/AmmDepositTest.java | 41 ++++++++++++ .../model/transactions/AmmWithdrawTest.java | 22 +++++++ .../org/xrpl/xrpl4j/tests/LedgerResultIT.java | 36 ++++++++++- 7 files changed, 199 insertions(+), 9 deletions(-) diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmBid.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmBid.java index 24872f827..b52da0635 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmBid.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmBid.java @@ -68,19 +68,35 @@ default TransactionFlags flags() { * Pay at least this amount for the slot. Setting this value higher makes it harder for others to outbid you. If * omitted, pay the minimum necessary to win the bid. * - * @return An optionally present {@link IssuedCurrencyAmount}. + *

+ * In a well-formed transaction, this field is always an {@link IssuedCurrencyAmount}. However, the XRPL will fail AMM + * transactions that specify {@link XrpCurrencyAmount}s with a {@code tec} error code, which means these malformed + * transactions can be included in validated ledgers. Therefore, this field is typed as a {@link CurrencyAmount} so + * that malformed transactions can be correctly deserialized. See #529 + *

+ * + * @return An optionally present {@link CurrencyAmount}. */ @JsonProperty("BidMin") - Optional bidMin(); + Optional bidMin(); /** * Pay at most this amount for the slot. If the cost to win the bid is higher than this amount, the transaction fails. * If omitted, pay as much as necessary to win the bid. * - * @return An optionally present {@link IssuedCurrencyAmount}. + *

+ * In a well-formed transaction, this field is always an {@link IssuedCurrencyAmount}. However, the XRPL will fail AMM + * transactions that specify {@link XrpCurrencyAmount}s with a {@code tec} error code, which means these malformed + * transactions can be included in validated ledgers. Therefore, this field is typed as a {@link CurrencyAmount} so + * that malformed transactions can be correctly deserialized. See #529 + *

+ * + * @return An optionally present {@link CurrencyAmount}. */ @JsonProperty("BidMax") - Optional bidMax(); + Optional bidMax(); /** * A list of up to 4 additional accounts that you allow to trade at the discounted fee. This cannot include the diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmDeposit.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmDeposit.java index 1336e27a6..72bc376c0 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmDeposit.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmDeposit.java @@ -84,10 +84,18 @@ static ImmutableAmmDeposit.Builder builder() { /** * How many of the AMM's LP Tokens to buy. * - * @return An optionally present {@link IssuedCurrencyAmount}. + *

+ * In a well-formed transaction, this field is always an {@link IssuedCurrencyAmount}. However, the XRPL will fail AMM + * transactions that specify {@link XrpCurrencyAmount}s with a {@code tec} error code, which means these malformed + * transactions can be included in validated ledgers. Therefore, this field is typed as a {@link CurrencyAmount} so + * that malformed transactions can be correctly deserialized. See #529 + *

+ * + * @return An optionally present {@link CurrencyAmount}. */ @JsonProperty("LPTokenOut") - Optional lpTokenOut(); + Optional lpTokenOut(); /** * An optional {@link TradingFee} to set on the AMM instance. This field is only honored if the AMM's LP token balance diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmWithdraw.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmWithdraw.java index 3e0998fde..89ad06bec 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmWithdraw.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmWithdraw.java @@ -86,9 +86,17 @@ static ImmutableAmmWithdraw.Builder builder() { /** * How many of the AMM's LP Tokens to buy. * + *

+ * In a well-formed transaction, this field is always an {@link IssuedCurrencyAmount}. However, the XRPL will fail AMM + * transactions that specify {@link XrpCurrencyAmount}s with a {@code tec} error code, which means these malformed + * transactions can be included in validated ledgers. Therefore, this field is typed as a {@link CurrencyAmount} so + * that malformed transactions can be correctly deserialized. See #529 + *

+ * * @return An optionally present {@link IssuedCurrencyAmount}. */ @JsonProperty("LPTokensIn") - Optional lpTokensIn(); + Optional lpTokensIn(); } diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmBidTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmBidTest.java index 91f51139b..0975e3aa0 100644 --- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmBidTest.java +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmBidTest.java @@ -5,6 +5,7 @@ import org.json.JSONException; import org.junit.jupiter.api.Test; import org.xrpl.xrpl4j.crypto.keys.PublicKey; +import org.xrpl.xrpl4j.crypto.signing.Signature; import org.xrpl.xrpl4j.model.AbstractJsonTest; import org.xrpl.xrpl4j.model.flags.TransactionFlags; import org.xrpl.xrpl4j.model.ledger.AuthAccount; @@ -249,4 +250,66 @@ void testJsonWithMinAndMax() throws JSONException, JsonProcessingException { assertCanSerializeAndDeserialize(bid, json); } + + /** + * Test that ensures the problematic transaction found in #529 is deserializable. + */ + @Test + void testJsonWithXrpAmountBidMinAndMax() throws JSONException, JsonProcessingException { + AmmBid ammBid = AmmBid.builder() + .account(Address.of("rammersz4CroiyvbkzeZN1sBDCK9P8DvxF")) + .asset(Issue.XRP) + .asset2( + Issue.builder() + .issuer(Address.of("rswh1fvyLqHizBS2awu1vs6QcmwTBd9qiv")) + .currency("XAH") + .build() + ) + .addAuthAccounts( + AuthAccountWrapper.of( + AuthAccount.of(Address.of("rapido5rxPmP4YkMZZEeXSHqWefxHEkqv6")) + ) + ) + .bidMax(XrpCurrencyAmount.ofDrops(10)) + .bidMin(XrpCurrencyAmount.ofDrops(10)) + .fee(XrpCurrencyAmount.ofDrops(10)) + .flags(TransactionFlags.FULLY_CANONICAL_SIG) + .sequence(UnsignedInteger.valueOf(87704195)) + .signingPublicKey( + PublicKey.fromBase16EncodedPublicKey("ED2D15BC6B61D6520011E4C794C5B320E584106154D0865BB095D70DA9A2A57B57") + ) + .transactionSignature( + Signature.fromBase16("F652BD5369F6EE9A8A1490BD37B8240CEE2B4B6EF94D22EC2DBB6912AA729B829" + + "FC3D7E24B30A1E6CC11F868CE229B105398719152B9BEE8992A56D654F79C0A") + ) + .build(); + String json = "{\n" + + " \"Account\": \"rammersz4CroiyvbkzeZN1sBDCK9P8DvxF\",\n" + + " \"Asset\": {\n" + + " \"currency\": \"XRP\"\n" + + " },\n" + + " \"Asset2\": {\n" + + " \"currency\": \"XAH\",\n" + + " \"issuer\": \"rswh1fvyLqHizBS2awu1vs6QcmwTBd9qiv\"\n" + + " },\n" + + " \"AuthAccounts\": [\n" + + " {\n" + + " \"AuthAccount\": {\n" + + " \"Account\": \"rapido5rxPmP4YkMZZEeXSHqWefxHEkqv6\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"BidMax\": \"10\",\n" + + " \"BidMin\": \"10\",\n" + + " \"Fee\": \"10\",\n" + + " \"Flags\": 2147483648,\n" + + " \"Sequence\": 87704195,\n" + + " \"SigningPubKey\": \"ED2D15BC6B61D6520011E4C794C5B320E584106154D0865BB095D70DA9A2A57B57\",\n" + + " \"TransactionType\": \"AMMBid\",\n" + + " \"TxnSignature\": \"F652BD5369F6EE9A8A1490BD37B8240CEE2B4B6EF94D22EC2DBB6912AA729B829FC3D7E24B30A" + + "1E6CC11F868CE229B105398719152B9BEE8992A56D654F79C0A\"\n" + + "}"; + assertCanSerializeAndDeserialize(ammBid, json); + } } \ No newline at end of file diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmDepositTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmDepositTest.java index 9f4c5c1f9..004816e7d 100644 --- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmDepositTest.java +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmDepositTest.java @@ -70,6 +70,47 @@ void constructLpTokenDepositAndTestJson() throws JSONException, JsonProcessingEx assertCanSerializeAndDeserialize(deposit, json); } + @Test + void constructLpTokenDepositWithXrpLpTokenAmountAndTestJson() throws JSONException, JsonProcessingException { + AmmDeposit deposit = AmmDeposit.builder() + .account(Address.of("rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm")) + .fee(XrpCurrencyAmount.ofDrops(10)) + .signingPublicKey( + PublicKey.fromBase16EncodedPublicKey("02356E89059A75438887F9FEE2056A2890DB82A68353BE9C0C0C8F89C0018B37FC") + ) + .flags(AmmDepositFlags.LP_TOKEN) + .asset(Issue.XRP) + .asset2( + Issue.builder() + .issuer(Address.of("rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd")) + .currency("TST") + .build() + ) + .lpTokenOut(XrpCurrencyAmount.ofDrops(10)) + .build(); + + assertThat(deposit.flags()).isEqualTo(AmmDepositFlags.LP_TOKEN); + + String json = "{\n" + + " \"Account\" : \"" + deposit.account() + "\",\n" + + " \"LPTokenOut\" : \"10\",\n" + + " \"Asset2\" : {\n" + + " \"currency\" : \"TST\",\n" + + " \"issuer\" : \"rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd\"\n" + + " },\n" + + " \"Asset\" : {\n" + + " \"currency\" : \"XRP\"\n" + + " },\n" + + " \"Fee\" : \"10\",\n" + + " \"Flags\" : " + AmmDepositFlags.LP_TOKEN + ",\n" + + " \"Sequence\" : 0,\n" + + " \"SigningPubKey\" : \"02356E89059A75438887F9FEE2056A2890DB82A68353BE9C0C0C8F89C0018B37FC\",\n" + + " \"TransactionType\" : \"AMMDeposit\"\n" + + "}"; + + assertCanSerializeAndDeserialize(deposit, json); + } + @Test void constructTwoAssetDepositAndTestJson() throws JSONException, JsonProcessingException { AmmDeposit deposit = AmmDeposit.builder() diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmWithdrawTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmWithdrawTest.java index 493af7fe3..8f89e64ff 100644 --- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmWithdrawTest.java +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmWithdrawTest.java @@ -34,6 +34,28 @@ void constructLpTokenWithdrawAndTestJson() throws JSONException, JsonProcessingE assertCanSerializeAndDeserialize(withdraw, json); } + @Test + void constructLpTokenWithdrawWithXrpCurrencyAmountAndTestJson() throws JSONException, JsonProcessingException { + AmmWithdraw withdraw = baseBuilder() + .flags(AmmWithdrawFlags.LP_TOKEN) + .lpTokensIn(XrpCurrencyAmount.ofDrops(10)) + .build(); + + String json = "{\n" + + " \"Account\" : \"rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm\",\n" + + " \"LPTokensIn\" : \"10\"," + + " \"Asset\" : " + objectMapper.writeValueAsString(withdraw.asset()) + "," + + " \"Asset2\" : " + objectMapper.writeValueAsString(withdraw.asset2()) + "," + + " \"Fee\" : \"10\",\n" + + " \"Flags\" : " + AmmWithdrawFlags.LP_TOKEN + ",\n" + + " \"Sequence\" : 0,\n" + + " \"SigningPubKey\" : \"02356E89059A75438887F9FEE2056A2890DB82A68353BE9C0C0C8F89C0018B37FC\",\n" + + " \"TransactionType\" : \"AMMWithdraw\"\n" + + "}"; + + assertCanSerializeAndDeserialize(withdraw, json); + } + @Test void constructWithdrawAllAndTestJson() throws JSONException, JsonProcessingException { AmmWithdraw withdraw = baseBuilder() diff --git a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/LedgerResultIT.java b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/LedgerResultIT.java index de2809483..cf135b60a 100644 --- a/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/LedgerResultIT.java +++ b/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/LedgerResultIT.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. @@ -25,9 +25,17 @@ import org.junit.jupiter.api.Test; import org.xrpl.xrpl4j.client.JsonRpcClientErrorException; +import org.xrpl.xrpl4j.client.XrplClient; import org.xrpl.xrpl4j.model.client.common.LedgerSpecifier; import org.xrpl.xrpl4j.model.client.ledger.LedgerRequestParams; import org.xrpl.xrpl4j.model.client.ledger.LedgerResult; +import org.xrpl.xrpl4j.model.client.transactions.TransactionResult; +import org.xrpl.xrpl4j.model.transactions.AmmBid; +import org.xrpl.xrpl4j.model.transactions.Hash256; +import org.xrpl.xrpl4j.model.transactions.Transaction; +import org.xrpl.xrpl4j.tests.environment.XrplEnvironment; + +import java.util.Optional; /** * These tests ensure {@link LedgerResult}s can be constructed from any JSON responses rippled sends back. @@ -88,4 +96,28 @@ void getClosedLedgerResult() throws JsonRpcClientErrorException { assertThat(ledgerResult.ledger().closeTimeHuman()).isNotEmpty(); assertThat(ledgerResult.ledger().parentCloseTime()).isNotEmpty(); } + + /** + * Pulls down ledger BAA4AF508E9A9CB7685D9E61B82486681E52E9B920904B0650499497F050D8FA, which had an + * {@link org.xrpl.xrpl4j.model.transactions.AmmBid} transaction with an + * {@link org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount} in the {@link AmmBid#bidMax()} field. + */ + @Test + void canDeserializeLedger_Issue529() throws JsonRpcClientErrorException { + XrplClient mainnetClient = XrplEnvironment.getConfiguredMainnetEnvironment().getXrplClient(); + LedgerResult ledger = mainnetClient.ledger( + LedgerRequestParams.builder() + .transactions(true) + .ledgerSpecifier( + LedgerSpecifier.of(Hash256.of("BAA4AF508E9A9CB7685D9E61B82486681E52E9B920904B0650499497F050D8FA"))) + .build() + ); + + Optional> problematicTransaction = ledger.ledger().transactions().stream() + .filter(transaction -> transaction.hash() + .equals(Hash256.of("6A8BC948E1309219EA8E14905D0EA9BB94E24429DE5B15CDE8916CDBCE42034B"))) + .findFirst(); + + assertThat(problematicTransaction).isNotEmpty(); + } }