diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AccountSet.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AccountSet.java index be1af6b7a..800ee3e78 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AccountSet.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AccountSet.java @@ -22,6 +22,8 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -261,6 +263,7 @@ default AccountSet normalizeSetFlag() { * @return An {@link Optional} of type {@link String} containing the domain. */ @JsonProperty("Domain") + @JsonInclude(Include.NON_ABSENT) Optional domain(); /** diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java index 524737872..7e9ebd316 100644 --- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/BinarySerializationTests.java @@ -136,6 +136,36 @@ public void serializeAccountSetTransactionWithNetworkId() throws JsonProcessingE assertSerializesAndDeserializes(accountSet, expectedBinary); } + @Test + public void serializeAccountSetTransactionWithDomain() throws JsonProcessingException { + AccountSet accountSet = AccountSet.builder() + .account(Address.of("rpP2GdsQwenNnFPefbXFgiTvEgJWQpq8Rw")) + .fee(XrpCurrencyAmount.ofDrops(10)) + .sequence(UnsignedInteger.valueOf(10598)) + .networkId(NetworkId.of(UnsignedInteger.MAX_VALUE)) + .domain("ABCD") + .build(); + + String expectedBinary = "12000321FFFFFFFF240000296668400000000000000A73007702ABCD81140F3D0C7D2CFAB2EC8" + + "295451F0B3CA038E8E9CDCD"; + assertSerializesAndDeserializes(accountSet, expectedBinary); + } + + @Test + public void serializeAccountSetTransactionWithEmptyStringDomain() throws JsonProcessingException { + AccountSet accountSet = AccountSet.builder() + .account(Address.of("rpP2GdsQwenNnFPefbXFgiTvEgJWQpq8Rw")) + .fee(XrpCurrencyAmount.ofDrops(10)) + .sequence(UnsignedInteger.valueOf(10598)) + .networkId(NetworkId.of(UnsignedInteger.MAX_VALUE)) + .domain("") + .build(); + + String expectedBinary = "12000321FFFFFFFF240000296668400000000000000A7300770081140F3D0C7D2CFAB2EC829545" + + "1F0B3CA038E8E9CDCD"; + assertSerializesAndDeserializes(accountSet, expectedBinary); + } + @Test public void serializeAccountSetTransactionWithEmptyFlags() throws JsonProcessingException { AccountSet accountSet = AccountSet.builder() diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/json/AccountSetJsonTests.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/json/AccountSetJsonTests.java index 6f6447209..9487cc2fd 100644 --- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/json/AccountSetJsonTests.java +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/json/AccountSetJsonTests.java @@ -80,6 +80,88 @@ public void fullyPopulatedAccountSet() throws JSONException, JsonProcessingExcep assertCanSerializeAndDeserialize(accountSet, json); } + @Test + public void accountSetWithEmptyDomain() throws JSONException, JsonProcessingException { + AccountSet accountSet = AccountSet.builder() + .account(Address.of("rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn")) + .fee(XrpCurrencyAmount.ofDrops(12)) + .sequence(UnsignedInteger.valueOf(5)) + .setFlag(AccountSetFlag.ACCOUNT_TXN_ID) + .messageKey("03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB") + .transferRate(UnsignedInteger.valueOf(1000000001)) + .tickSize(UnsignedInteger.valueOf(15)) + .clearFlag(AccountSetFlag.DEFAULT_RIPPLE) + .emailHash("f9879d71855b5ff21e4963273a886bfc") + .signingPublicKey( + PublicKey.fromBase16EncodedPublicKey("02356E89059A75438887F9FEE2056A2890DB82A68353BE9C0C0C8F89C0018B37FC") + ) + .flags(AccountSetTransactionFlags.of(TransactionFlags.FULLY_CANONICAL_SIG.getValue())) + .mintAccount(Address.of("rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn")) + .networkId(NetworkId.of(1024)) + .build(); + + String json = "{\n" + + " \"TransactionType\":\"AccountSet\",\n" + + " \"Account\":\"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn\",\n" + + " \"Fee\":\"12\",\n" + + " \"Sequence\":5,\n" + + " \"Flags\":2147483648,\n" + + " \"SetFlag\":5,\n" + + " \"MessageKey\":\"03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB\",\n" + + " \"TransferRate\":1000000001,\n" + + " \"TickSize\":15,\n" + + " \"ClearFlag\":8,\n" + + " \"SigningPubKey\" : \"02356E89059A75438887F9FEE2056A2890DB82A68353BE9C0C0C8F89C0018B37FC\",\n" + + " \"NFTokenMinter\" : \"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn\",\n" + + " \"NetworkID\": 1024,\n" + + " \"EmailHash\":\"f9879d71855b5ff21e4963273a886bfc\"\n" + + "}"; + + assertCanSerializeAndDeserialize(accountSet, json); + } + + @Test + public void accountSetWithEmptyStringDomain() throws JSONException, JsonProcessingException { + AccountSet accountSet = AccountSet.builder() + .account(Address.of("rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn")) + .fee(XrpCurrencyAmount.ofDrops(12)) + .domain("") + .sequence(UnsignedInteger.valueOf(5)) + .setFlag(AccountSetFlag.ACCOUNT_TXN_ID) + .messageKey("03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB") + .transferRate(UnsignedInteger.valueOf(1000000001)) + .tickSize(UnsignedInteger.valueOf(15)) + .clearFlag(AccountSetFlag.DEFAULT_RIPPLE) + .emailHash("f9879d71855b5ff21e4963273a886bfc") + .signingPublicKey( + PublicKey.fromBase16EncodedPublicKey("02356E89059A75438887F9FEE2056A2890DB82A68353BE9C0C0C8F89C0018B37FC") + ) + .flags(AccountSetTransactionFlags.of(TransactionFlags.FULLY_CANONICAL_SIG.getValue())) + .mintAccount(Address.of("rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn")) + .networkId(NetworkId.of(1024)) + .build(); + + String json = "{\n" + + " \"TransactionType\":\"AccountSet\",\n" + + " \"Account\":\"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn\",\n" + + " \"Fee\":\"12\",\n" + + " \"Sequence\":5,\n" + + " \"Flags\":2147483648,\n" + + " \"Domain\":\"\",\n" + + " \"SetFlag\":5,\n" + + " \"MessageKey\":\"03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB\",\n" + + " \"TransferRate\":1000000001,\n" + + " \"TickSize\":15,\n" + + " \"ClearFlag\":8,\n" + + " \"SigningPubKey\" : \"02356E89059A75438887F9FEE2056A2890DB82A68353BE9C0C0C8F89C0018B37FC\",\n" + + " \"NFTokenMinter\" : \"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn\",\n" + + " \"NetworkID\": 1024,\n" + + " \"EmailHash\":\"f9879d71855b5ff21e4963273a886bfc\"\n" + + "}"; + + assertCanSerializeAndDeserialize(accountSet, json); + } + @Test public void testJsonWithUnsetFlags() throws JsonProcessingException, JSONException { AccountSet accountSet = AccountSet.builder() 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 18e2e9378..582e3892f 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 @@ -392,6 +392,72 @@ void submitAndRetrieveAccountSetWithZeroClearFlagAndSetFlag() assertThat(accountSetTransactionResult.transaction().clearFlag()).isNotEmpty().get().isEqualTo(AccountSetFlag.NONE); } + @Test + void setAndUnsetDomain() throws JsonRpcClientErrorException, JsonProcessingException { + KeyPair keyPair = constructRandomAccount(); + + /////////////////////// + // Get validated account info and validate account state + AccountInfoResult accountInfo = this.scanForResult( + () -> this.getValidatedAccountInfo(keyPair.publicKey().deriveAddress()) + ); + + FeeResult feeResult = xrplClient.fee(); + AccountSet setDomain = AccountSet.builder() + .account(keyPair.publicKey().deriveAddress()) + .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee()) + .sequence(accountInfo.accountData().sequence()) + .signingPublicKey(keyPair.publicKey()) + .domain("ABCD") + .build(); + + SingleSignedTransaction signedSetDomain = signatureService.sign( + keyPair.privateKey(), setDomain + ); + SubmitResult response = xrplClient.submit(signedSetDomain); + + assertThat(response.engineResult()).isEqualTo("tesSUCCESS"); + assertThat(signedSetDomain.hash()).isEqualTo(response.transactionResult().hash()); + logger.info( + "AccountSet transaction successful: https://testnet.xrpl.org/transactions/" + response.transactionResult().hash() + ); + + this.scanForResult(() -> + this.getValidatedTransaction(signedSetDomain.hash(), AccountSet.class) + ); + accountInfo = this.scanForResult( + () -> this.getValidatedAccountInfo(keyPair.publicKey().deriveAddress()) + ); + assertThat(accountInfo.accountData().domain()).isNotEmpty().isEqualTo(setDomain.domain()); + + AccountSet clearDomain = AccountSet.builder() + .account(keyPair.publicKey().deriveAddress()) + .fee(FeeUtils.computeNetworkFees(feeResult).recommendedFee()) + .sequence(accountInfo.accountData().sequence()) + .signingPublicKey(keyPair.publicKey()) + .domain("") + .build(); + + SingleSignedTransaction signedClearDomain = signatureService.sign( + keyPair.privateKey(), clearDomain + ); + SubmitResult clearDomainSubmitResult = xrplClient.submit(signedClearDomain); + + assertThat(clearDomainSubmitResult.engineResult()).isEqualTo("tesSUCCESS"); + assertThat(signedClearDomain.hash()).isEqualTo(clearDomainSubmitResult.transactionResult().hash()); + logger.info( + "AccountSet transaction successful: https://testnet.xrpl.org/transactions/" + + clearDomainSubmitResult.transactionResult().hash() + ); + + this.scanForResult(() -> + this.getValidatedTransaction(signedClearDomain.hash(), AccountSet.class) + ); + accountInfo = this.scanForResult( + () -> this.getValidatedAccountInfo(keyPair.publicKey().deriveAddress()) + ); + assertThat(accountInfo.accountData().domain()).isEmpty(); + } ////////////////////// // Test Helpers