Skip to content

Commit e2a61dc

Browse files
committed
Merge branch 'main' of github.com:XRPLF/xrpl4j into releases/v3.3
2 parents 4a4eda1 + 55975e1 commit e2a61dc

File tree

12 files changed

+228
-27
lines changed

12 files changed

+228
-27
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ current [BOM](https://howtodoinjava.com/maven/maven-bom-bill-of-materials-depend
3333
<dependency>
3434
<groupId>org.xrpl</groupId>
3535
<artifactId>xrpl4j-bom</artifactId>
36-
<version>3.2.1</version>
36+
<version>3.3.0</version>
3737
<type>pom</type>
3838
<scope>import</scope>
3939
</dependency>

xrpl4j-bom/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ POM file. For example:
2020
<dependency>
2121
<groupId>org.xrpl.xrpl4j</groupId>
2222
<artifactId>xrpl4j-bom</artifactId>
23-
<version>3.2.1</version>
23+
<version>3.3.0</version>
2424
<type>pom</type>
2525
<scope>import</scope>
2626
</dependency>

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmBid.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,35 @@ default TransactionFlags flags() {
6868
* Pay at least this amount for the slot. Setting this value higher makes it harder for others to outbid you. If
6969
* omitted, pay the minimum necessary to win the bid.
7070
*
71-
* @return An optionally present {@link IssuedCurrencyAmount}.
71+
* <p>
72+
* In a well-formed transaction, this field is always an {@link IssuedCurrencyAmount}. However, the XRPL will fail AMM
73+
* transactions that specify {@link XrpCurrencyAmount}s with a {@code tec} error code, which means these malformed
74+
* transactions can be included in validated ledgers. Therefore, this field is typed as a {@link CurrencyAmount} so
75+
* that malformed transactions can be correctly deserialized. See <a
76+
* href="https://github.com/XRPLF/xrpl4j/issues/529">#529</a>
77+
* </p>
78+
*
79+
* @return An optionally present {@link CurrencyAmount}.
7280
*/
7381
@JsonProperty("BidMin")
74-
Optional<IssuedCurrencyAmount> bidMin();
82+
Optional<CurrencyAmount> bidMin();
7583

7684
/**
7785
* Pay at most this amount for the slot. If the cost to win the bid is higher than this amount, the transaction fails.
7886
* If omitted, pay as much as necessary to win the bid.
7987
*
80-
* @return An optionally present {@link IssuedCurrencyAmount}.
88+
* <p>
89+
* In a well-formed transaction, this field is always an {@link IssuedCurrencyAmount}. However, the XRPL will fail AMM
90+
* transactions that specify {@link XrpCurrencyAmount}s with a {@code tec} error code, which means these malformed
91+
* transactions can be included in validated ledgers. Therefore, this field is typed as a {@link CurrencyAmount} so
92+
* that malformed transactions can be correctly deserialized. See <a
93+
* href="https://github.com/XRPLF/xrpl4j/issues/529">#529</a>
94+
* </p>
95+
*
96+
* @return An optionally present {@link CurrencyAmount}.
8197
*/
8298
@JsonProperty("BidMax")
83-
Optional<IssuedCurrencyAmount> bidMax();
99+
Optional<CurrencyAmount> bidMax();
84100

85101
/**
86102
* A list of up to 4 additional accounts that you allow to trade at the discounted fee. This cannot include the

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmDeposit.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,18 @@ static ImmutableAmmDeposit.Builder builder() {
8484
/**
8585
* How many of the AMM's LP Tokens to buy.
8686
*
87-
* @return An optionally present {@link IssuedCurrencyAmount}.
87+
* <p>
88+
* In a well-formed transaction, this field is always an {@link IssuedCurrencyAmount}. However, the XRPL will fail AMM
89+
* transactions that specify {@link XrpCurrencyAmount}s with a {@code tec} error code, which means these malformed
90+
* transactions can be included in validated ledgers. Therefore, this field is typed as a {@link CurrencyAmount} so
91+
* that malformed transactions can be correctly deserialized. See <a
92+
* href="https://github.com/XRPLF/xrpl4j/issues/529">#529</a>
93+
* </p>
94+
*
95+
* @return An optionally present {@link CurrencyAmount}.
8896
*/
8997
@JsonProperty("LPTokenOut")
90-
Optional<IssuedCurrencyAmount> lpTokenOut();
98+
Optional<CurrencyAmount> lpTokenOut();
9199

92100
/**
93101
* An optional {@link TradingFee} to set on the AMM instance. This field is only honored if the AMM's LP token balance

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmWithdraw.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,17 @@ static ImmutableAmmWithdraw.Builder builder() {
8686
/**
8787
* How many of the AMM's LP Tokens to buy.
8888
*
89+
* <p>
90+
* In a well-formed transaction, this field is always an {@link IssuedCurrencyAmount}. However, the XRPL will fail AMM
91+
* transactions that specify {@link XrpCurrencyAmount}s with a {@code tec} error code, which means these malformed
92+
* transactions can be included in validated ledgers. Therefore, this field is typed as a {@link CurrencyAmount} so
93+
* that malformed transactions can be correctly deserialized. See <a
94+
* href="https://github.com/XRPLF/xrpl4j/issues/529">#529</a>
95+
* </p>
96+
*
8997
* @return An optionally present {@link IssuedCurrencyAmount}.
9098
*/
9199
@JsonProperty("LPTokensIn")
92-
Optional<IssuedCurrencyAmount> lpTokensIn();
100+
Optional<CurrencyAmount> lpTokensIn();
93101

94102
}

xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmBidTest.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.json.JSONException;
66
import org.junit.jupiter.api.Test;
77
import org.xrpl.xrpl4j.crypto.keys.PublicKey;
8+
import org.xrpl.xrpl4j.crypto.signing.Signature;
89
import org.xrpl.xrpl4j.model.AbstractJsonTest;
910
import org.xrpl.xrpl4j.model.flags.TransactionFlags;
1011
import org.xrpl.xrpl4j.model.ledger.AuthAccount;
@@ -249,4 +250,66 @@ void testJsonWithMinAndMax() throws JSONException, JsonProcessingException {
249250

250251
assertCanSerializeAndDeserialize(bid, json);
251252
}
253+
254+
/**
255+
* Test that ensures the problematic transaction found in <a
256+
* href="https://github.com/XRPLF/xrpl4j/issues/529">#529</a> is deserializable.
257+
*/
258+
@Test
259+
void testJsonWithXrpAmountBidMinAndMax() throws JSONException, JsonProcessingException {
260+
AmmBid ammBid = AmmBid.builder()
261+
.account(Address.of("rammersz4CroiyvbkzeZN1sBDCK9P8DvxF"))
262+
.asset(Issue.XRP)
263+
.asset2(
264+
Issue.builder()
265+
.issuer(Address.of("rswh1fvyLqHizBS2awu1vs6QcmwTBd9qiv"))
266+
.currency("XAH")
267+
.build()
268+
)
269+
.addAuthAccounts(
270+
AuthAccountWrapper.of(
271+
AuthAccount.of(Address.of("rapido5rxPmP4YkMZZEeXSHqWefxHEkqv6"))
272+
)
273+
)
274+
.bidMax(XrpCurrencyAmount.ofDrops(10))
275+
.bidMin(XrpCurrencyAmount.ofDrops(10))
276+
.fee(XrpCurrencyAmount.ofDrops(10))
277+
.flags(TransactionFlags.FULLY_CANONICAL_SIG)
278+
.sequence(UnsignedInteger.valueOf(87704195))
279+
.signingPublicKey(
280+
PublicKey.fromBase16EncodedPublicKey("ED2D15BC6B61D6520011E4C794C5B320E584106154D0865BB095D70DA9A2A57B57")
281+
)
282+
.transactionSignature(
283+
Signature.fromBase16("F652BD5369F6EE9A8A1490BD37B8240CEE2B4B6EF94D22EC2DBB6912AA729B829" +
284+
"FC3D7E24B30A1E6CC11F868CE229B105398719152B9BEE8992A56D654F79C0A")
285+
)
286+
.build();
287+
String json = "{\n" +
288+
" \"Account\": \"rammersz4CroiyvbkzeZN1sBDCK9P8DvxF\",\n" +
289+
" \"Asset\": {\n" +
290+
" \"currency\": \"XRP\"\n" +
291+
" },\n" +
292+
" \"Asset2\": {\n" +
293+
" \"currency\": \"XAH\",\n" +
294+
" \"issuer\": \"rswh1fvyLqHizBS2awu1vs6QcmwTBd9qiv\"\n" +
295+
" },\n" +
296+
" \"AuthAccounts\": [\n" +
297+
" {\n" +
298+
" \"AuthAccount\": {\n" +
299+
" \"Account\": \"rapido5rxPmP4YkMZZEeXSHqWefxHEkqv6\"\n" +
300+
" }\n" +
301+
" }\n" +
302+
" ],\n" +
303+
" \"BidMax\": \"10\",\n" +
304+
" \"BidMin\": \"10\",\n" +
305+
" \"Fee\": \"10\",\n" +
306+
" \"Flags\": 2147483648,\n" +
307+
" \"Sequence\": 87704195,\n" +
308+
" \"SigningPubKey\": \"ED2D15BC6B61D6520011E4C794C5B320E584106154D0865BB095D70DA9A2A57B57\",\n" +
309+
" \"TransactionType\": \"AMMBid\",\n" +
310+
" \"TxnSignature\": \"F652BD5369F6EE9A8A1490BD37B8240CEE2B4B6EF94D22EC2DBB6912AA729B829FC3D7E24B30A" +
311+
"1E6CC11F868CE229B105398719152B9BEE8992A56D654F79C0A\"\n" +
312+
"}";
313+
assertCanSerializeAndDeserialize(ammBid, json);
314+
}
252315
}

xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmDepositTest.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,47 @@ void constructLpTokenDepositAndTestJson() throws JSONException, JsonProcessingEx
7070
assertCanSerializeAndDeserialize(deposit, json);
7171
}
7272

73+
@Test
74+
void constructLpTokenDepositWithXrpLpTokenAmountAndTestJson() throws JSONException, JsonProcessingException {
75+
AmmDeposit deposit = AmmDeposit.builder()
76+
.account(Address.of("rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm"))
77+
.fee(XrpCurrencyAmount.ofDrops(10))
78+
.signingPublicKey(
79+
PublicKey.fromBase16EncodedPublicKey("02356E89059A75438887F9FEE2056A2890DB82A68353BE9C0C0C8F89C0018B37FC")
80+
)
81+
.flags(AmmDepositFlags.LP_TOKEN)
82+
.asset(Issue.XRP)
83+
.asset2(
84+
Issue.builder()
85+
.issuer(Address.of("rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"))
86+
.currency("TST")
87+
.build()
88+
)
89+
.lpTokenOut(XrpCurrencyAmount.ofDrops(10))
90+
.build();
91+
92+
assertThat(deposit.flags()).isEqualTo(AmmDepositFlags.LP_TOKEN);
93+
94+
String json = "{\n" +
95+
" \"Account\" : \"" + deposit.account() + "\",\n" +
96+
" \"LPTokenOut\" : \"10\",\n" +
97+
" \"Asset2\" : {\n" +
98+
" \"currency\" : \"TST\",\n" +
99+
" \"issuer\" : \"rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd\"\n" +
100+
" },\n" +
101+
" \"Asset\" : {\n" +
102+
" \"currency\" : \"XRP\"\n" +
103+
" },\n" +
104+
" \"Fee\" : \"10\",\n" +
105+
" \"Flags\" : " + AmmDepositFlags.LP_TOKEN + ",\n" +
106+
" \"Sequence\" : 0,\n" +
107+
" \"SigningPubKey\" : \"02356E89059A75438887F9FEE2056A2890DB82A68353BE9C0C0C8F89C0018B37FC\",\n" +
108+
" \"TransactionType\" : \"AMMDeposit\"\n" +
109+
"}";
110+
111+
assertCanSerializeAndDeserialize(deposit, json);
112+
}
113+
73114
@Test
74115
void constructTwoAssetDepositAndTestJson() throws JSONException, JsonProcessingException {
75116
AmmDeposit deposit = AmmDeposit.builder()

xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/AmmWithdrawTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,28 @@ void constructLpTokenWithdrawAndTestJson() throws JSONException, JsonProcessingE
3434
assertCanSerializeAndDeserialize(withdraw, json);
3535
}
3636

37+
@Test
38+
void constructLpTokenWithdrawWithXrpCurrencyAmountAndTestJson() throws JSONException, JsonProcessingException {
39+
AmmWithdraw withdraw = baseBuilder()
40+
.flags(AmmWithdrawFlags.LP_TOKEN)
41+
.lpTokensIn(XrpCurrencyAmount.ofDrops(10))
42+
.build();
43+
44+
String json = "{\n" +
45+
" \"Account\" : \"rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm\",\n" +
46+
" \"LPTokensIn\" : \"10\"," +
47+
" \"Asset\" : " + objectMapper.writeValueAsString(withdraw.asset()) + "," +
48+
" \"Asset2\" : " + objectMapper.writeValueAsString(withdraw.asset2()) + "," +
49+
" \"Fee\" : \"10\",\n" +
50+
" \"Flags\" : " + AmmWithdrawFlags.LP_TOKEN + ",\n" +
51+
" \"Sequence\" : 0,\n" +
52+
" \"SigningPubKey\" : \"02356E89059A75438887F9FEE2056A2890DB82A68353BE9C0C0C8F89C0018B37FC\",\n" +
53+
" \"TransactionType\" : \"AMMWithdraw\"\n" +
54+
"}";
55+
56+
assertCanSerializeAndDeserialize(withdraw, json);
57+
}
58+
3759
@Test
3860
void constructWithdrawAllAndTestJson() throws JSONException, JsonProcessingException {
3961
AmmWithdraw withdraw = baseBuilder()

xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/AmmIT.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ void depositAndVoteOnTradingFee() throws JsonRpcClientErrorException, JsonProces
144144
TradingFee expectedTradingFee = TradingFee.ofPercent(
145145
issuerLpTokenBalance.multiply(amm.amm().tradingFee().bigDecimalValue()).add(
146146
traderLpTokenBalance.multiply(newTradingFee.bigDecimalValue())
147-
).divide(issuerLpTokenBalance.add(traderLpTokenBalance), RoundingMode.FLOOR)
148-
.setScale(3, RoundingMode.FLOOR)
147+
).divide(issuerLpTokenBalance.add(traderLpTokenBalance), RoundingMode.HALF_UP)
148+
.setScale(3, RoundingMode.HALF_UP)
149149
);
150150

151151
AmmInfoResult ammAfterVote = getAmmInfo(issuerKeyPair);
@@ -255,7 +255,7 @@ void depositAndWithdraw() throws JsonRpcClientErrorException, JsonProcessingExce
255255
.build()
256256
)
257257
.asset(Issue.XRP)
258-
.amount(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(90)))
258+
.amount(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(9)))
259259
.flags(AmmWithdrawFlags.SINGLE_ASSET)
260260
.build();
261261

@@ -296,7 +296,7 @@ private AccountInfoResult depositXrp(
296296
SignatureService<PrivateKey> signatureService,
297297
FeeResult feeResult
298298
) throws JsonRpcClientErrorException, JsonProcessingException {
299-
XrpCurrencyAmount depositAmount = XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(100));
299+
XrpCurrencyAmount depositAmount = XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(10));
300300
AmmDeposit deposit = AmmDeposit.builder()
301301
.account(traderAccount.accountData().account())
302302
.asset2(
@@ -373,10 +373,10 @@ private AmmInfoResult createAmm(
373373
IssuedCurrencyAmount.builder()
374374
.issuer(issuerKeyPair.publicKey().deriveAddress())
375375
.currency(xrpl4jCoin)
376-
.value("25")
376+
.value("2.5")
377377
.build()
378378
)
379-
.amount2(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(100)))
379+
.amount2(XrpCurrencyAmount.ofXrp(BigDecimal.valueOf(10)))
380380
.tradingFee(TradingFee.ofPercent(BigDecimal.ONE))
381381
.lastLedgerSequence(issuerAccount.ledgerIndexSafe().plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue())
382382
.signingPublicKey(issuerKeyPair.publicKey())

xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests/LedgerResultIT.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
* Licensed under the Apache License, Version 2.0 (the "License");
1010
* you may not use this file except in compliance with the License.
1111
* You may obtain a copy of the License at
12-
*
12+
*
1313
* http://www.apache.org/licenses/LICENSE-2.0
14-
*
14+
*
1515
* Unless required by applicable law or agreed to in writing, software
1616
* distributed under the License is distributed on an "AS IS" BASIS,
1717
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -25,9 +25,17 @@
2525

2626
import org.junit.jupiter.api.Test;
2727
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
28+
import org.xrpl.xrpl4j.client.XrplClient;
2829
import org.xrpl.xrpl4j.model.client.common.LedgerSpecifier;
2930
import org.xrpl.xrpl4j.model.client.ledger.LedgerRequestParams;
3031
import org.xrpl.xrpl4j.model.client.ledger.LedgerResult;
32+
import org.xrpl.xrpl4j.model.client.transactions.TransactionResult;
33+
import org.xrpl.xrpl4j.model.transactions.AmmBid;
34+
import org.xrpl.xrpl4j.model.transactions.Hash256;
35+
import org.xrpl.xrpl4j.model.transactions.Transaction;
36+
import org.xrpl.xrpl4j.tests.environment.XrplEnvironment;
37+
38+
import java.util.Optional;
3139

3240
/**
3341
* These tests ensure {@link LedgerResult}s can be constructed from any JSON responses rippled sends back.
@@ -88,4 +96,28 @@ void getClosedLedgerResult() throws JsonRpcClientErrorException {
8896
assertThat(ledgerResult.ledger().closeTimeHuman()).isNotEmpty();
8997
assertThat(ledgerResult.ledger().parentCloseTime()).isNotEmpty();
9098
}
99+
100+
/**
101+
* Pulls down ledger BAA4AF508E9A9CB7685D9E61B82486681E52E9B920904B0650499497F050D8FA, which had an
102+
* {@link org.xrpl.xrpl4j.model.transactions.AmmBid} transaction with an
103+
* {@link org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount} in the {@link AmmBid#bidMax()} field.
104+
*/
105+
@Test
106+
void canDeserializeLedger_Issue529() throws JsonRpcClientErrorException {
107+
XrplClient mainnetClient = XrplEnvironment.getConfiguredMainnetEnvironment().getXrplClient();
108+
LedgerResult ledger = mainnetClient.ledger(
109+
LedgerRequestParams.builder()
110+
.transactions(true)
111+
.ledgerSpecifier(
112+
LedgerSpecifier.of(Hash256.of("BAA4AF508E9A9CB7685D9E61B82486681E52E9B920904B0650499497F050D8FA")))
113+
.build()
114+
);
115+
116+
Optional<TransactionResult<? extends Transaction>> problematicTransaction = ledger.ledger().transactions().stream()
117+
.filter(transaction -> transaction.hash()
118+
.equals(Hash256.of("6A8BC948E1309219EA8E14905D0EA9BB94E24429DE5B15CDE8916CDBCE42034B")))
119+
.findFirst();
120+
121+
assertThat(problematicTransaction).isNotEmpty();
122+
}
91123
}

0 commit comments

Comments
 (0)