Skip to content

Commit 87f4af5

Browse files
authored
#576: Add support for AMMClawback (#601)
* Generate definitions.json from xrpl.js script * Add AmmClawback transaction and transaction flags * Add AmmClawback to signature utils * Add Unit and Integration tests
1 parent 3153d8d commit 87f4af5

File tree

11 files changed

+993
-5
lines changed

11 files changed

+993
-5
lines changed

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtils.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.xrpl.xrpl4j.model.transactions.AccountSet;
3535
import org.xrpl.xrpl4j.model.transactions.Address;
3636
import org.xrpl.xrpl4j.model.transactions.AmmBid;
37+
import org.xrpl.xrpl4j.model.transactions.AmmClawback;
3738
import org.xrpl.xrpl4j.model.transactions.AmmCreate;
3839
import org.xrpl.xrpl4j.model.transactions.AmmDelete;
3940
import org.xrpl.xrpl4j.model.transactions.AmmDeposit;
@@ -395,6 +396,10 @@ public <T extends Transaction> SingleSignedTransaction<T> addSignatureToTransact
395396
transactionWithSignature = OracleDelete.builder().from((OracleDelete) transaction)
396397
.transactionSignature(signature)
397398
.build();
399+
} else if (AmmClawback.class.isAssignableFrom(transaction.getClass())) {
400+
transactionWithSignature = AmmClawback.builder().from((AmmClawback) transaction)
401+
.transactionSignature(signature)
402+
.build();
398403
} else if (MpTokenAuthorize.class.isAssignableFrom(transaction.getClass())) {
399404
transactionWithSignature = MpTokenAuthorize.builder().from((MpTokenAuthorize) transaction)
400405
.transactionSignature(signature)
@@ -622,6 +627,10 @@ public <T extends Transaction> T addMultiSignaturesToTransaction(T transaction,
622627
transactionWithSignatures = OracleDelete.builder().from((OracleDelete) transaction)
623628
.signers(signers)
624629
.build();
630+
} else if (AmmClawback.class.isAssignableFrom(transaction.getClass())) {
631+
transactionWithSignatures = AmmClawback.builder().from((AmmClawback) transaction)
632+
.signers(signers)
633+
.build();
625634
} else if (MpTokenAuthorize.class.isAssignableFrom(transaction.getClass())) {
626635
transactionWithSignatures = MpTokenAuthorize.builder().from((MpTokenAuthorize) transaction)
627636
.signers(signers)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.xrpl.xrpl4j.model.flags;
2+
3+
/*-
4+
* ========================LICENSE_START=================================
5+
* xrpl4j :: core
6+
* %%
7+
* Copyright (C) 2020 - 2023 XRPL Foundation and its contributors
8+
* %%
9+
* Licensed under the Apache License, Version 2.0 (the "License");
10+
* you may not use this file except in compliance with the License.
11+
* You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS,
17+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* See the License for the specific language governing permissions and
19+
* limitations under the License.
20+
* =========================LICENSE_END==================================
21+
*/
22+
23+
import org.xrpl.xrpl4j.model.transactions.AmmClawback;
24+
25+
/**
26+
* {@link TransactionFlags} for {@link AmmClawback} transactions.
27+
*/
28+
public class AmmClawbackFlags extends TransactionFlags {
29+
/**
30+
* Constant {@link AmmDepositFlags} for the {@code tfClawTwoAssets} flag.
31+
*/
32+
public static final AmmClawbackFlags CLAW_TWO_ASSETS = new AmmClawbackFlags(0x00000001);
33+
34+
/**
35+
* Constant {@link AmmDepositFlags} for an unset value for "flags".
36+
*/
37+
public static final AmmClawbackFlags UNSET = new AmmClawbackFlags(0L);
38+
39+
private AmmClawbackFlags(long value) {
40+
super(value);
41+
}
42+
43+
private AmmClawbackFlags() {
44+
}
45+
46+
/**
47+
* Construct an empty instance of {@link AmmClawbackFlags}. Transactions with empty flags will
48+
* not be serialized with a {@code Flags} field.
49+
*
50+
* @return An empty {@link AmmClawbackFlags}.
51+
*/
52+
public static AmmClawbackFlags empty() {
53+
return new AmmClawbackFlags();
54+
}
55+
56+
/**
57+
* Whether the {@code tfClawTwoAssets} flag is set.
58+
*
59+
* @return {@code true} if {@code tfLPToken} is set, otherwise {@code false}.
60+
*/
61+
public boolean tfClawTwoAssets() {
62+
return this.isSet(CLAW_TWO_ASSETS);
63+
}
64+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package org.xrpl.xrpl4j.model.transactions;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
6+
import com.google.common.annotations.Beta;
7+
import org.immutables.value.Value;
8+
import org.xrpl.xrpl4j.model.flags.AmmClawbackFlags;
9+
import org.xrpl.xrpl4j.model.ledger.Issue;
10+
11+
import java.util.Optional;
12+
13+
/**
14+
* An {@link AmmClawback} transaction claws back tokens from a holder that has funds in an AMM pool.
15+
*/
16+
@Value.Immutable
17+
@JsonSerialize(as = ImmutableAmmClawback.class)
18+
@JsonDeserialize(as = ImmutableAmmClawback.class)
19+
public interface AmmClawback extends Transaction {
20+
21+
/**
22+
* Construct a builder for this class.
23+
*
24+
* @return An {@link ImmutableAmmClawback.Builder}.
25+
*/
26+
static ImmutableAmmClawback.Builder builder() {
27+
return ImmutableAmmClawback.builder();
28+
}
29+
30+
/**
31+
* The address of the holder that has funds deposited in the AMM pool.
32+
*
33+
* @return An {@link Address}.
34+
*/
35+
@JsonProperty("Holder")
36+
Address holder();
37+
38+
/**
39+
* The asset in the AMM pool that the issuer is looking to claw back.
40+
*
41+
* @return An {@link Issue}.
42+
*/
43+
@JsonProperty("Asset")
44+
Issue asset();
45+
46+
/**
47+
* Other asset in the AMM pool that the issuer is looking to claw back.
48+
*
49+
* @return An {@link Issue}.
50+
*/
51+
@JsonProperty("Asset2")
52+
Issue asset2();
53+
54+
/**
55+
* Optional field that specifies the maximum amount to clawback from the AMM pool.
56+
*
57+
* @return An {@link CurrencyAmount}.
58+
*/
59+
@JsonProperty("Amount")
60+
Optional<CurrencyAmount> amount();
61+
62+
/**
63+
* Transaction Flags for {@link AmmClawback}, with the only option being tfClawTwoAssets.
64+
*
65+
* @return {@link AmmClawbackFlags#UNSET} if field was not set, otherwise returns with the set flag.
66+
*/
67+
@JsonProperty("Flags")
68+
@Value.Default
69+
default AmmClawbackFlags flags() {
70+
return AmmClawbackFlags.empty();
71+
}
72+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public interface Transaction {
9999
.put(ImmutableMpTokenIssuanceDestroy.class, TransactionType.MPT_ISSUANCE_DESTROY)
100100
.put(ImmutableMpTokenIssuanceSet.class, TransactionType.MPT_ISSUANCE_SET)
101101
.put(ImmutableUnknownTransaction.class, TransactionType.UNKNOWN)
102+
.put(ImmutableAmmClawback.class, TransactionType.AMM_CLAWBACK)
102103
.build();
103104

104105
/**

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ public enum TransactionType {
338338
@Beta
339339
ORACLE_DELETE("OracleDelete"),
340340

341+
/**
342+
* The {@link TransactionType} for the {@link AmmClawback} transaction.
343+
*/
344+
AMM_CLAWBACK("AMMClawback"),
341345
@Beta
342346
MPT_ISSUANCE_CREATE("MPTokenIssuanceCreate"),
343347
@Beta

xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/signing/SignatureUtilsTest.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import org.xrpl.xrpl4j.model.transactions.AccountSet;
6464
import org.xrpl.xrpl4j.model.transactions.Address;
6565
import org.xrpl.xrpl4j.model.transactions.AmmBid;
66+
import org.xrpl.xrpl4j.model.transactions.AmmClawback;
6667
import org.xrpl.xrpl4j.model.transactions.AmmCreate;
6768
import org.xrpl.xrpl4j.model.transactions.AmmDelete;
6869
import org.xrpl.xrpl4j.model.transactions.AmmDeposit;
@@ -850,6 +851,59 @@ void addSignatureToAmmCreate() {
850851
addSignatureToTransactionHelper(ammCreate);
851852
}
852853

854+
@Test
855+
void addSignatureToAmmClawback() {
856+
AmmClawback ammClawback = AmmClawback.builder()
857+
.account(sourcePublicKey.deriveAddress())
858+
.holder(sourcePublicKey.deriveAddress())
859+
.amount(
860+
IssuedCurrencyAmount.builder()
861+
.currency("TST")
862+
.issuer(Address.of("rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"))
863+
.value("25")
864+
.build()
865+
)
866+
.asset(Issue.XRP)
867+
.asset2(
868+
Issue.builder()
869+
.issuer(Address.of("rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"))
870+
.currency("TST")
871+
.build()
872+
)
873+
.fee(XrpCurrencyAmount.ofDrops(10))
874+
.sequence(UnsignedInteger.valueOf(6))
875+
.signingPublicKey(sourcePublicKey)
876+
.build();
877+
878+
addSignatureToTransactionHelper(ammClawback);
879+
}
880+
881+
@Test
882+
void addMultiSignaturesToAmmClawback() {
883+
AmmClawback ammClawback = AmmClawback.builder()
884+
.account(sourcePublicKey.deriveAddress())
885+
.holder(sourcePublicKey.deriveAddress())
886+
.amount(
887+
IssuedCurrencyAmount.builder()
888+
.currency("TST")
889+
.issuer(Address.of("rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"))
890+
.value("25")
891+
.build()
892+
)
893+
.asset(Issue.XRP)
894+
.asset2(
895+
Issue.builder()
896+
.issuer(Address.of("rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"))
897+
.currency("TST")
898+
.build()
899+
)
900+
.fee(XrpCurrencyAmount.ofDrops(10))
901+
.sequence(UnsignedInteger.valueOf(6))
902+
.build();
903+
904+
addMultiSignatureToTransactionHelper(ammClawback);
905+
}
906+
853907
@Test
854908
void addSignatureToAmmDeposit() {
855909
AmmDeposit deposit = AmmDeposit.builder()
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.xrpl.xrpl4j.model.flags;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import com.fasterxml.jackson.core.JsonProcessingException;
6+
import org.json.JSONException;
7+
import org.junit.jupiter.api.Test;
8+
9+
class AmmClawbackFlagsTest extends AbstractFlagsTest {
10+
11+
@Test
12+
void testFlagWithValue() {
13+
AmmClawbackFlags flags = AmmClawbackFlags.CLAW_TWO_ASSETS;
14+
assertThat(flags.isEmpty()).isFalse();
15+
16+
assertThat(flags.tfClawTwoAssets()).isTrue();
17+
assertThat(flags.tfFullyCanonicalSig()).isFalse();
18+
assertThat(flags.getValue()).isEqualTo(1L);
19+
}
20+
21+
@Test
22+
void testEmptyFlags() {
23+
AmmClawbackFlags flags = AmmClawbackFlags.empty();
24+
assertThat(flags.isEmpty()).isTrue();
25+
26+
assertThat(flags.tfClawTwoAssets()).isFalse();
27+
assertThat(flags.tfFullyCanonicalSig()).isFalse();
28+
assertThat(flags.getValue()).isZero();
29+
}
30+
31+
@Test
32+
void testJson() throws JSONException, JsonProcessingException {
33+
TransactionFlagsWrapper wrapper = TransactionFlagsWrapper.of(AmmClawbackFlags.CLAW_TWO_ASSETS);
34+
String json = String.format("{\n" +
35+
" \"flags\": %s\n" +
36+
"}", AmmClawbackFlags.CLAW_TWO_ASSETS.getValue());
37+
38+
assertCanSerializeAndDeserialize(wrapper, json);
39+
}
40+
41+
@Test
42+
void testEmptyJson() throws JSONException, JsonProcessingException {
43+
AmmClawbackFlags flags = AmmClawbackFlags.empty();
44+
AbstractFlagsTest.TransactionFlagsWrapper wrapper = AbstractFlagsTest.TransactionFlagsWrapper.of(flags);
45+
String json = "{\n" +
46+
"}";
47+
48+
assertCanSerializeAndDeserialize(wrapper, json);
49+
}
50+
}

0 commit comments

Comments
 (0)