diff --git a/src/main/java/org/stellar/sdk/BumpFootprintExpirationOperation.java b/src/main/java/org/stellar/sdk/BumpFootprintExpirationOperation.java new file mode 100644 index 000000000..4949a5ea5 --- /dev/null +++ b/src/main/java/org/stellar/sdk/BumpFootprintExpirationOperation.java @@ -0,0 +1,71 @@ +package org.stellar.sdk; + +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import org.stellar.sdk.xdr.BumpFootprintExpirationOp; +import org.stellar.sdk.xdr.ExtensionPoint; +import org.stellar.sdk.xdr.OperationType; +import org.stellar.sdk.xdr.Uint32; + +/** + * Represents BumpFootprintExpiration operation. + * + *

Bump the expiration of a footprint (read and written ledger keys). + * + * @see List of Operations + */ +@EqualsAndHashCode(callSuper = true) +@SuperBuilder(toBuilder = true) +@Value +public class BumpFootprintExpirationOperation extends Operation { + + /** + * the number of ledgers past the LCL (last closed ledger) by which to extend the validity of the + * ledger keys in this transaction + */ + @NonNull Integer ledgersToExpire; + + /** + * Constructs a new BumpFootprintExpirationOperation object from the XDR representation of the + * {@link BumpFootprintExpirationOperation}. + * + * @param op the XDR representation of the {@link BumpFootprintExpirationOperation}. + */ + public static BumpFootprintExpirationOperation fromXdr(BumpFootprintExpirationOp op) { + return BumpFootprintExpirationOperation.builder() + .ledgersToExpire(op.getLedgersToExpire().getUint32()) + .build(); + } + + @Override + org.stellar.sdk.xdr.Operation.OperationBody toOperationBody(AccountConverter accountConverter) { + BumpFootprintExpirationOp op = new BumpFootprintExpirationOp(); + op.setExt(new ExtensionPoint.Builder().discriminant(0).build()); + op.setLedgersToExpire(new Uint32(ledgersToExpire)); + + org.stellar.sdk.xdr.Operation.OperationBody body = + new org.stellar.sdk.xdr.Operation.OperationBody(); + body.setDiscriminant(OperationType.BUMP_FOOTPRINT_EXPIRATION); + body.setBumpFootprintExpirationOp(op); + return body; + } + + /** Customizing builder methods. Rest of the builder code will be auto generated by Lombok. */ + public abstract static class BumpFootprintExpirationOperationBuilder< + C extends BumpFootprintExpirationOperation, + B extends BumpFootprintExpirationOperationBuilder> + extends OperationBuilder { + public B ledgersToExpire(Integer ledgersToExpire) { + if (ledgersToExpire <= 0) { + throw new IllegalArgumentException("ledgersToExpire isn't a ledger quantity (uint32)"); + } + this.ledgersToExpire = ledgersToExpire; + return self(); + } + } +} diff --git a/src/main/java/org/stellar/sdk/InvokeHostFunctionOperation.java b/src/main/java/org/stellar/sdk/InvokeHostFunctionOperation.java index e0ed9cccd..914c547e1 100644 --- a/src/main/java/org/stellar/sdk/InvokeHostFunctionOperation.java +++ b/src/main/java/org/stellar/sdk/InvokeHostFunctionOperation.java @@ -14,7 +14,7 @@ /** * Represents InvokeHostFunction operation. * * @see RestoreFootprint operation. + * + * @see List of Operations + */ +@EqualsAndHashCode(callSuper = true) +@SuperBuilder(toBuilder = true) +@Value +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class RestoreFootprintOperation extends Operation { + /** + * Constructs a new RestoreFootprintOperation object from the XDR representation of the {@link + * RestoreFootprintOperation}. + * + * @param op the XDR representation of the {@link RestoreFootprintOperation}. + */ + public static RestoreFootprintOperation fromXdr(RestoreFootprintOp op) { + return new RestoreFootprintOperation(); + } + + @Override + org.stellar.sdk.xdr.Operation.OperationBody toOperationBody(AccountConverter accountConverter) { + RestoreFootprintOp op = new RestoreFootprintOp(); + op.setExt(new ExtensionPoint.Builder().discriminant(0).build()); + + org.stellar.sdk.xdr.Operation.OperationBody body = + new org.stellar.sdk.xdr.Operation.OperationBody(); + body.setDiscriminant(OperationType.RESTORE_FOOTPRINT); + body.setRestoreFootprintOp(op); + return body; + } +} diff --git a/src/main/java/org/stellar/sdk/responses/OperationDeserializer.java b/src/main/java/org/stellar/sdk/responses/OperationDeserializer.java index 961cc1474..550cad8ab 100644 --- a/src/main/java/org/stellar/sdk/responses/OperationDeserializer.java +++ b/src/main/java/org/stellar/sdk/responses/OperationDeserializer.java @@ -89,6 +89,10 @@ public OperationResponse deserialize( return gson.fromJson(json, LiquidityPoolWithdrawOperationResponse.class); case INVOKE_HOST_FUNCTION: return gson.fromJson(json, InvokeHostFunctionOperationResponse.class); + case BUMP_FOOTPRINT_EXPIRATION: + return gson.fromJson(json, BumpFootprintExpirationOperationResponse.class); + case RESTORE_FOOTPRINT: + return gson.fromJson(json, RestoreFootprintOperationResponse.class); default: throw new RuntimeException("Invalid operation type"); } diff --git a/src/main/java/org/stellar/sdk/responses/operations/BumpFootprintExpirationOperationResponse.java b/src/main/java/org/stellar/sdk/responses/operations/BumpFootprintExpirationOperationResponse.java new file mode 100644 index 000000000..1e23f0ac4 --- /dev/null +++ b/src/main/java/org/stellar/sdk/responses/operations/BumpFootprintExpirationOperationResponse.java @@ -0,0 +1,27 @@ +package org.stellar.sdk.responses.operations; + +import com.google.gson.annotations.SerializedName; + +/** + * Represents BumpFootprintExpiration operation response. + * + * @see Horizon + * Protocol + * @see Operation documentation + * @see org.stellar.sdk.requests.OperationsRequestBuilder + * @see org.stellar.sdk.Server#operations() + */ +public class BumpFootprintExpirationOperationResponse extends OperationResponse { + @SerializedName("ledgers_to_expire") + private final Long ledgersToExpire; + + public BumpFootprintExpirationOperationResponse(Long ledgersToExpire) { + this.ledgersToExpire = ledgersToExpire; + } + + public Long getLedgersToExpire() { + return ledgersToExpire; + } +} diff --git a/src/main/java/org/stellar/sdk/responses/operations/InvokeHostFunctionOperationResponse.java b/src/main/java/org/stellar/sdk/responses/operations/InvokeHostFunctionOperationResponse.java index 47a677921..45764b231 100644 --- a/src/main/java/org/stellar/sdk/responses/operations/InvokeHostFunctionOperationResponse.java +++ b/src/main/java/org/stellar/sdk/responses/operations/InvokeHostFunctionOperationResponse.java @@ -7,6 +7,9 @@ /** * Represents InvokeHostFunction operation response. * + * @see Horizon + * Protocol * @see Operation documentation * @see org.stellar.sdk.requests.OperationsRequestBuilder diff --git a/src/main/java/org/stellar/sdk/responses/operations/RestoreFootprintOperationResponse.java b/src/main/java/org/stellar/sdk/responses/operations/RestoreFootprintOperationResponse.java new file mode 100644 index 000000000..f6795f56c --- /dev/null +++ b/src/main/java/org/stellar/sdk/responses/operations/RestoreFootprintOperationResponse.java @@ -0,0 +1,14 @@ +package org.stellar.sdk.responses.operations; + +/** + * Represents RestoreFootprint operation response. + * + * @see Horizon + * Protocol + * @see Operation documentation + * @see org.stellar.sdk.requests.OperationsRequestBuilder + * @see org.stellar.sdk.Server#operations() + */ +public class RestoreFootprintOperationResponse extends OperationResponse {} diff --git a/src/test/java/org/stellar/sdk/BumpFootprintExpirationOperationTest.java b/src/test/java/org/stellar/sdk/BumpFootprintExpirationOperationTest.java new file mode 100644 index 000000000..21411c5df --- /dev/null +++ b/src/test/java/org/stellar/sdk/BumpFootprintExpirationOperationTest.java @@ -0,0 +1,111 @@ +package org.stellar.sdk; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNull; + +import org.junit.Assert; +import org.junit.Test; + +public class BumpFootprintExpirationOperationTest { + @Test + public void testBuilderWithSource() { + String source = "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW"; + BumpFootprintExpirationOperation op = + BumpFootprintExpirationOperation.builder() + .ledgersToExpire(123) + .sourceAccount(source) + .build(); + assertEquals(Integer.valueOf(123), op.getLedgersToExpire()); + assertEquals(source, op.getSourceAccount()); + String expectXdr = "AAAAAQAAAAAk4TTtavBWsGnEN3KxHw4Ohwi22ZJHWi8hlamN5pm0TgAAABkAAAAAAAAAew=="; + assertEquals(expectXdr, op.toXdrBase64()); + } + + @Test + public void testBuilderWithoutSource() { + BumpFootprintExpirationOperation op = + BumpFootprintExpirationOperation.builder().ledgersToExpire(123).build(); + assertEquals(Integer.valueOf(123), op.getLedgersToExpire()); + assertNull(op.getSourceAccount()); + String expectXdr = "AAAAAAAAABkAAAAAAAAAew=="; + assertEquals(expectXdr, op.toXdrBase64()); + } + + @Test + public void testFromXdr() { + String source = "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW"; + BumpFootprintExpirationOperation originOp = + BumpFootprintExpirationOperation.builder() + .ledgersToExpire(123) + .sourceAccount(source) + .build(); + org.stellar.sdk.xdr.Operation xdrObject = originOp.toXdr(); + Operation restartOp = Operation.fromXdr(xdrObject); + Assert.assertEquals(restartOp, originOp); + } + + @Test + public void testEquals() { + String source = "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW"; + BumpFootprintExpirationOperation operation1 = + BumpFootprintExpirationOperation.builder() + .ledgersToExpire(123) + .sourceAccount(source) + .build(); + BumpFootprintExpirationOperation operation2 = + BumpFootprintExpirationOperation.builder() + .ledgersToExpire(123) + .sourceAccount(source) + .build(); + assertEquals(operation1, operation2); + } + + @Test + public void testNotEquals() { + String source = "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW"; + BumpFootprintExpirationOperation operation1 = + BumpFootprintExpirationOperation.builder() + .ledgersToExpire(123) + .sourceAccount(source) + .build(); + BumpFootprintExpirationOperation operation2 = + BumpFootprintExpirationOperation.builder() + .ledgersToExpire(124) + .sourceAccount(source) + .build(); + Assert.assertNotEquals(operation1, operation2); + } + + @Test + public void testNotEqualsSource() { + String source = "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW"; + BumpFootprintExpirationOperation operation1 = + BumpFootprintExpirationOperation.builder() + .ledgersToExpire(123) + .sourceAccount(source) + .build(); + BumpFootprintExpirationOperation operation2 = + BumpFootprintExpirationOperation.builder().ledgersToExpire(123).build(); + Assert.assertNotEquals(operation1, operation2); + } + + @Test + public void testLedgersToExpireIsInvalidThrows() { + try { + BumpFootprintExpirationOperation.builder().ledgersToExpire(-1).build(); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertEquals("ledgersToExpire isn't a ledger quantity (uint32)", e.getMessage()); + } + } + + @Test + public void testLedgersToExpireIsNullThrows() { + try { + BumpFootprintExpirationOperation.builder().build(); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertEquals("ledgersToExpire is marked non-null but is null", e.getMessage()); + } + } +} diff --git a/src/test/java/org/stellar/sdk/RestoreFootprintOperationTest.java b/src/test/java/org/stellar/sdk/RestoreFootprintOperationTest.java new file mode 100644 index 000000000..ac55cd8dd --- /dev/null +++ b/src/test/java/org/stellar/sdk/RestoreFootprintOperationTest.java @@ -0,0 +1,56 @@ +package org.stellar.sdk; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNull; + +import org.junit.Assert; +import org.junit.Test; + +public class RestoreFootprintOperationTest { + @Test + public void testBuilderWithSource() { + String source = "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW"; + RestoreFootprintOperation op = + RestoreFootprintOperation.builder().sourceAccount(source).build(); + assertEquals(source, op.getSourceAccount()); + String expectXdr = "AAAAAQAAAAAk4TTtavBWsGnEN3KxHw4Ohwi22ZJHWi8hlamN5pm0TgAAABoAAAAA"; + assertEquals(expectXdr, op.toXdrBase64()); + } + + @Test + public void testBuilderWithoutSource() { + RestoreFootprintOperation op = RestoreFootprintOperation.builder().build(); + assertNull(op.getSourceAccount()); + String expectXdr = "AAAAAAAAABoAAAAA"; + assertEquals(expectXdr, op.toXdrBase64()); + } + + @Test + public void testFromXdr() { + String source = "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW"; + RestoreFootprintOperation originOp = + RestoreFootprintOperation.builder().sourceAccount(source).build(); + org.stellar.sdk.xdr.Operation xdrObject = originOp.toXdr(); + Operation restartOp = Operation.fromXdr(xdrObject); + Assert.assertEquals(restartOp, originOp); + } + + @Test + public void testEquals() { + String source = "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW"; + RestoreFootprintOperation operation1 = + RestoreFootprintOperation.builder().sourceAccount(source).build(); + RestoreFootprintOperation operation2 = + RestoreFootprintOperation.builder().sourceAccount(source).build(); + assertEquals(operation1, operation2); + } + + @Test + public void testNotEquals() { + String source = "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW"; + RestoreFootprintOperation operation1 = + RestoreFootprintOperation.builder().sourceAccount(source).build(); + RestoreFootprintOperation operation2 = RestoreFootprintOperation.builder().build(); + Assert.assertNotEquals(operation1, operation2); + } +} diff --git a/src/test/java/org/stellar/sdk/responses/OperationDeserializerTest.java b/src/test/java/org/stellar/sdk/responses/OperationDeserializerTest.java index 9bca0d33b..955b13eff 100644 --- a/src/test/java/org/stellar/sdk/responses/OperationDeserializerTest.java +++ b/src/test/java/org/stellar/sdk/responses/OperationDeserializerTest.java @@ -18,6 +18,7 @@ import org.stellar.sdk.Price; import org.stellar.sdk.responses.operations.AccountMergeOperationResponse; import org.stellar.sdk.responses.operations.AllowTrustOperationResponse; +import org.stellar.sdk.responses.operations.BumpFootprintExpirationOperationResponse; import org.stellar.sdk.responses.operations.BumpSequenceOperationResponse; import org.stellar.sdk.responses.operations.ChangeTrustOperationResponse; import org.stellar.sdk.responses.operations.ClaimClaimableBalanceOperationResponse; @@ -36,6 +37,7 @@ import org.stellar.sdk.responses.operations.PathPaymentStrictReceiveOperationResponse; import org.stellar.sdk.responses.operations.PathPaymentStrictSendOperationResponse; import org.stellar.sdk.responses.operations.PaymentOperationResponse; +import org.stellar.sdk.responses.operations.RestoreFootprintOperationResponse; import org.stellar.sdk.responses.operations.SetOptionsOperationResponse; import org.stellar.sdk.responses.operations.SetTrustLineFlagsOperationResponse; @@ -1956,4 +1958,102 @@ public void testDeserializeInvokeHostFunctionOperation() { "GBMLPRFCZDZJPKUPHUSHCKA737GOZL7ERZLGGMJ6YGHBFJZ6ZKMKCZTM"); assertEquals(operation.getAssetBalanceChanges().get(0).getAmount(), "500.0000000"); } + + @Test + public void testDeserializeBumpFootprintExpirationOperation() { + String json = + "{\n" + + " \"_links\": {\n" + + " \"self\": {\n" + + " \"href\": \"http://127.0.0.1:8000/operations/2224793063426\"\n" + + " },\n" + + " \"transaction\": {\n" + + " \"href\": \"http://127.0.0.1:8000/transactions/c452cd9d1ff9692499d0d2aa2f8e898b8c38025300c0f293f4a2adde7295c82f\"\n" + + " },\n" + + " \"effects\": {\n" + + " \"href\": \"http://127.0.0.1:8000/operations/2224793063426/effects\"\n" + + " },\n" + + " \"succeeds\": {\n" + + " \"href\": \"http://127.0.0.1:8000/effects?order=desc&cursor=2224793063426\"\n" + + " },\n" + + " \"precedes\": {\n" + + " \"href\": \"http://127.0.0.1:8000/effects?order=asc&cursor=2224793063426\"\n" + + " }\n" + + " },\n" + + " \"id\": \"2224793063426\",\n" + + " \"paging_token\": \"2224793063426\",\n" + + " \"transaction_successful\": true,\n" + + " \"source_account\": \"GDAT5HWTGIU4TSSZ4752OUC4SABDLTLZFRPZUJ3D6LKBNEPA7V2CIG54\",\n" + + " \"type\": \"bump_footprint_expiration\",\n" + + " \"type_i\": 25,\n" + + " \"created_at\": \"2023-07-20T10:44:56Z\",\n" + + " \"transaction_hash\": \"c452cd9d1ff9692499d0d2aa2f8e898b8c38025300c0f293f4a2adde7295c82f\",\n" + + " \"ledgers_to_expire\": \"2343241\"\n" + + "}"; + + BumpFootprintExpirationOperationResponse operation = + (BumpFootprintExpirationOperationResponse) + GsonSingleton.getInstance().fromJson(json, OperationResponse.class); + assertEquals( + operation.getLinks().getSelf().getHref(), "http://127.0.0.1:8000/operations/2224793063426"); + assertEquals(operation.getId().longValue(), 2224793063426L); + assertEquals(operation.getPagingToken(), "2224793063426"); + // assertEquals(operation.getTransactionSuccessful(), true); + assertEquals( + operation.getSourceAccount(), "GDAT5HWTGIU4TSSZ4752OUC4SABDLTLZFRPZUJ3D6LKBNEPA7V2CIG54"); + assertEquals(operation.getType(), "bump_footprint_expiration"); + assertEquals(operation.getCreatedAt(), "2023-07-20T10:44:56Z"); + assertEquals( + operation.getTransactionHash(), + "c452cd9d1ff9692499d0d2aa2f8e898b8c38025300c0f293f4a2adde7295c82f"); + assertEquals(operation.getLedgersToExpire().longValue(), 2343241); + } + + @Test + public void testDeserializeRestoreFootprintOperationResponse() { + String json = + "{\n" + + " \"_links\": {\n" + + " \"self\": {\n" + + " \"href\": \"http://127.0.0.1:8000/operations/2224793063427\"\n" + + " },\n" + + " \"transaction\": {\n" + + " \"href\": \"http://127.0.0.1:8000/transactions/b6932dacb25e05ca8e3d006d2a5a119683602f70474cc9f5de9fc53e99f627f8\"\n" + + " },\n" + + " \"effects\": {\n" + + " \"href\": \"http://127.0.0.1:8000/operations/2224793063427/effects\"\n" + + " },\n" + + " \"succeeds\": {\n" + + " \"href\": \"http://127.0.0.1:8000/effects?order=desc&cursor=2224793063427\"\n" + + " },\n" + + " \"precedes\": {\n" + + " \"href\": \"http://127.0.0.1:8000/effects?order=asc&cursor=2224793063427\"\n" + + " }\n" + + " },\n" + + " \"id\": \"2224793063427\",\n" + + " \"paging_token\": \"2224793063427\",\n" + + " \"transaction_successful\": true,\n" + + " \"source_account\": \"GDAT5HWTGIU4TSSZ4752OUC4SABDLTLZFRPZUJ3D6LKBNEPA7V2CIG54\",\n" + + " \"type\": \"restore_footprint\",\n" + + " \"type_i\": 26,\n" + + " \"created_at\": \"2023-07-20T10:44:56Z\",\n" + + " \"transaction_hash\": \"b6932dacb25e05ca8e3d006d2a5a119683602f70474cc9f5de9fc53e99f627f8\"\n" + + "}"; + + RestoreFootprintOperationResponse operation = + (RestoreFootprintOperationResponse) + GsonSingleton.getInstance().fromJson(json, OperationResponse.class); + assertEquals( + operation.getLinks().getSelf().getHref(), "http://127.0.0.1:8000/operations/2224793063427"); + assertEquals(operation.getId().longValue(), 2224793063427L); + assertEquals(operation.getPagingToken(), "2224793063427"); + // assertEquals(operation.getTransactionSuccessful(), true); + assertEquals( + operation.getSourceAccount(), "GDAT5HWTGIU4TSSZ4752OUC4SABDLTLZFRPZUJ3D6LKBNEPA7V2CIG54"); + assertEquals(operation.getType(), "restore_footprint"); + assertEquals(operation.getCreatedAt(), "2023-07-20T10:44:56Z"); + assertEquals( + operation.getTransactionHash(), + "b6932dacb25e05ca8e3d006d2a5a119683602f70474cc9f5de9fc53e99f627f8"); + } }