@@ -162,6 +162,119 @@ public void createAndFinishTimeBasedEscrow() throws JsonRpcClientErrorException,
162162
163163 }
164164
165+ /**
166+ * It is acceptable for an escrow to have the same source and destination accounts specified. This test verifies that
167+ * works properly when the escrow is finished.
168+ */
169+ @ Test
170+ public void createAndFinishTimeBasedEscrowToSelf () throws JsonRpcClientErrorException , JsonProcessingException {
171+ //////////////////////
172+ // Create random sender accounts
173+ KeyPair senderKeyPair = createRandomAccountEd25519 ();
174+
175+ //////////////////////
176+ // Sender account creates an Escrow with the receiver account
177+ FeeResult feeResult = xrplClient .fee ();
178+ final AccountInfoResult senderAccountInfo = this .scanForResult (
179+ () -> this .getValidatedAccountInfo (senderKeyPair .publicKey ().deriveAddress ())
180+ );
181+ assertThat (senderAccountInfo .accountData ().balance ()).isEqualTo (XrpCurrencyAmount .ofDrops (1000000000 ));
182+
183+ EscrowCreate escrowCreate = EscrowCreate .builder ()
184+ .account (senderKeyPair .publicKey ().deriveAddress ())
185+ .sequence (senderAccountInfo .accountData ().sequence ())
186+ .fee (feeResult .drops ().openLedgerFee ())
187+ .amount (XrpCurrencyAmount .ofDrops (123456 ))
188+ .destination (senderKeyPair .publicKey ().deriveAddress ())
189+ .cancelAfter (instantToXrpTimestamp (getMinExpirationTime ().plus (Duration .ofSeconds (100 ))))
190+ .finishAfter (instantToXrpTimestamp (getMinExpirationTime ().plus (Duration .ofSeconds (5 ))))
191+ .signingPublicKey (senderKeyPair .publicKey ())
192+ .build ();
193+
194+ //////////////////////
195+ // Submit the EscrowCreate transaction and validate that it was successful
196+ SingleSignedTransaction <EscrowCreate > signedEscrowCreate = signatureService .sign (
197+ senderKeyPair .privateKey (), escrowCreate
198+ );
199+ SubmitResult <EscrowCreate > createResult = xrplClient .submit (signedEscrowCreate );
200+ assertThat (createResult .engineResult ()).isEqualTo ("tesSUCCESS" );
201+ logger .info (
202+ "EscrowCreate transaction successful: https://testnet.xrpl.org/transactions/{}" ,
203+ createResult .transactionResult ().hash ()
204+ );
205+
206+ //////////////////////
207+ // Then wait until the transaction gets committed to a validated ledger
208+ TransactionResult <EscrowCreate > result = this .scanForResult (
209+ () -> this .getValidatedTransaction (createResult .transactionResult ().hash (), EscrowCreate .class )
210+ );
211+
212+ assertEntryEqualsObjectFromAccountObjects (
213+ senderKeyPair .publicKey ().deriveAddress (),
214+ escrowCreate .sequence ()
215+ );
216+
217+ //////////////////////
218+ // Wait until the close time on the current validated ledger is after the finishAfter time on the Escrow
219+ this .scanForResult (
220+ this ::getValidatedLedger ,
221+ ledgerResult ->
222+ FluentCompareTo .is (ledgerResult .ledger ().closeTime ().orElse (UnsignedLong .ZERO ))
223+ .greaterThan (
224+ createResult .transactionResult ().transaction ().finishAfter ()
225+ .map (finishAfter -> finishAfter .plus (UnsignedLong .valueOf (5 )))
226+ .orElse (UnsignedLong .MAX_VALUE )
227+ )
228+ );
229+
230+ final AccountInfoResult postEscrowCreateSenderAccountInfo = this .scanForResult (
231+ () -> this .getValidatedAccountInfo (senderKeyPair .publicKey ().deriveAddress ())
232+ );
233+ assertThat (postEscrowCreateSenderAccountInfo .accountData ().balance ())
234+ .isEqualTo (XrpCurrencyAmount .ofDrops (999876534 ));
235+
236+ //////////////////////
237+ // Receiver submits an EscrowFinish transaction to release the Escrow funds
238+ final AccountInfoResult preEscrowFinishSenderAccountInfo = this .scanForResult (
239+ () -> this .getValidatedAccountInfo (senderKeyPair .publicKey ().deriveAddress ())
240+ );
241+ EscrowFinish escrowFinish = EscrowFinish .builder ()
242+ .account (senderKeyPair .publicKey ().deriveAddress ())
243+ .fee (feeResult .drops ().openLedgerFee ())
244+ .sequence (preEscrowFinishSenderAccountInfo .accountData ().sequence ())
245+ .owner (senderKeyPair .publicKey ().deriveAddress ())
246+ .offerSequence (result .transaction ().sequence ())
247+ .signingPublicKey (senderKeyPair .publicKey ())
248+ .build ();
249+
250+ SingleSignedTransaction <EscrowFinish > signedEscrowFinish = signatureService .sign (
251+ senderKeyPair .privateKey (), escrowFinish
252+ );
253+ SubmitResult <EscrowFinish > finishResult = xrplClient .submit (signedEscrowFinish );
254+ assertThat (finishResult .engineResult ()).isEqualTo ("tesSUCCESS" );
255+ logger .info (
256+ "EscrowFinish transaction successful: https://testnet.xrpl.org/transactions/{}" ,
257+ finishResult .transactionResult ().hash ()
258+ );
259+
260+ //////////////////////
261+ // Wait for the EscrowFinish to get applied to a validated ledger
262+ this .scanForResult (
263+ () -> this .getValidatedTransaction (finishResult .transactionResult ().hash (), EscrowFinish .class )
264+ );
265+
266+ /////////////////////
267+ // Ensure that the funds were released to the receiver.
268+ this .scanForResult (
269+ () -> this .getValidatedAccountInfo (senderKeyPair .publicKey ().deriveAddress ()),
270+ infoResult -> infoResult .accountData ().balance ().equals (
271+ preEscrowFinishSenderAccountInfo .accountData ().balance ()
272+ .plus (escrowCreate .amount ())
273+ .minus (feeResult .drops ().openLedgerFee ()))
274+ && infoResult .accountData ().balance ().equals (XrpCurrencyAmount .ofDrops (999999980 ))
275+ );
276+ }
277+
165278 @ Test
166279 public void createAndCancelTimeBasedEscrow () throws JsonRpcClientErrorException , JsonProcessingException {
167280 //////////////////////
@@ -269,6 +382,119 @@ public void createAndCancelTimeBasedEscrow() throws JsonRpcClientErrorException,
269382 );
270383 }
271384
385+ /**
386+ * It is acceptable for an escrow to have the same source and destination accounts specified. This test verifies that
387+ * works properly when the escrow is cancelled.
388+ */
389+ @ Test
390+ public void createAndCancelTimeBasedEscrowToSelf () throws JsonRpcClientErrorException , JsonProcessingException {
391+ //////////////////////
392+ // Create random sender accounts
393+ KeyPair senderKeyPair = createRandomAccountEd25519 ();
394+
395+ //////////////////////
396+ // Sender account creates an Escrow with the receiver account
397+ FeeResult feeResult = xrplClient .fee ();
398+ final AccountInfoResult senderAccountInfo = this .scanForResult (
399+ () -> this .getValidatedAccountInfo (senderKeyPair .publicKey ().deriveAddress ())
400+ );
401+ assertThat (senderAccountInfo .accountData ().balance ()).isEqualTo (XrpCurrencyAmount .ofDrops (1000000000 ));
402+
403+ EscrowCreate escrowCreate = EscrowCreate .builder ()
404+ .account (senderKeyPair .publicKey ().deriveAddress ())
405+ .sequence (senderAccountInfo .accountData ().sequence ())
406+ .fee (feeResult .drops ().openLedgerFee ())
407+ .amount (XrpCurrencyAmount .ofDrops (123456 ))
408+ .destination (senderKeyPair .publicKey ().deriveAddress ())
409+ .cancelAfter (instantToXrpTimestamp (getMinExpirationTime ().plus (Duration .ofSeconds (100 ))))
410+ .finishAfter (instantToXrpTimestamp (getMinExpirationTime ().plus (Duration .ofSeconds (95 ))))
411+ .signingPublicKey (senderKeyPair .publicKey ())
412+ .build ();
413+
414+ //////////////////////
415+ // Submit the EscrowCreate transaction and validate that it was successful
416+ SingleSignedTransaction <EscrowCreate > signedEscrowCreate = signatureService .sign (
417+ senderKeyPair .privateKey (), escrowCreate
418+ );
419+ SubmitResult <EscrowCreate > createResult = xrplClient .submit (signedEscrowCreate );
420+ assertThat (createResult .engineResult ()).isEqualTo ("tesSUCCESS" );
421+ logger .info (
422+ "EscrowCreate transaction successful: https://testnet.xrpl.org/transactions/{}" ,
423+ createResult .transactionResult ().hash ()
424+ );
425+
426+ //////////////////////
427+ // Then wait until the transaction gets committed to a validated ledger
428+ TransactionResult <EscrowCreate > result = this .scanForResult (
429+ () -> this .getValidatedTransaction (createResult .transactionResult ().hash (), EscrowCreate .class )
430+ );
431+
432+ assertEntryEqualsObjectFromAccountObjects (
433+ senderKeyPair .publicKey ().deriveAddress (),
434+ escrowCreate .sequence ()
435+ );
436+
437+ //////////////////////
438+ // Wait until the close time on the current validated ledger is after the finishAfter time on the Escrow
439+ this .scanForResult (
440+ this ::getValidatedLedger ,
441+ ledgerResult ->
442+ FluentCompareTo .is (ledgerResult .ledger ().closeTime ().orElse (UnsignedLong .ZERO ))
443+ .greaterThan (
444+ createResult .transactionResult ().transaction ().finishAfter ()
445+ .map (finishAfter -> finishAfter .plus (UnsignedLong .valueOf (5 )))
446+ .orElse (UnsignedLong .MAX_VALUE )
447+ )
448+ );
449+
450+ final AccountInfoResult postEscrowCreateSenderAccountInfo = this .scanForResult (
451+ () -> this .getValidatedAccountInfo (senderKeyPair .publicKey ().deriveAddress ())
452+ );
453+ assertThat (postEscrowCreateSenderAccountInfo .accountData ().balance ())
454+ .isEqualTo (XrpCurrencyAmount .ofDrops (999876534 ));
455+
456+ //////////////////////
457+ // Receiver submits an EscrowFinish transaction to release the Escrow funds
458+ final AccountInfoResult preEscrowFinishSenderAccountInfo = this .scanForResult (
459+ () -> this .getValidatedAccountInfo (senderKeyPair .publicKey ().deriveAddress ())
460+ );
461+ EscrowCancel escrowCancel = EscrowCancel .builder ()
462+ .account (senderKeyPair .publicKey ().deriveAddress ())
463+ .fee (feeResult .drops ().openLedgerFee ())
464+ .sequence (preEscrowFinishSenderAccountInfo .accountData ().sequence ())
465+ .owner (senderKeyPair .publicKey ().deriveAddress ())
466+ .offerSequence (result .transaction ().sequence ())
467+ .signingPublicKey (senderKeyPair .publicKey ())
468+ .build ();
469+
470+ SingleSignedTransaction <EscrowCancel > signedEscrowCancel = signatureService .sign (
471+ senderKeyPair .privateKey (), escrowCancel
472+ );
473+ SubmitResult <EscrowCancel > cancelResult = xrplClient .submit (signedEscrowCancel );
474+ assertThat (cancelResult .engineResult ()).isEqualTo ("tesSUCCESS" );
475+ logger .info (
476+ "EscrowFinish transaction successful: https://testnet.xrpl.org/transactions/{}" ,
477+ cancelResult .transactionResult ().hash ()
478+ );
479+
480+ //////////////////////
481+ // Wait for the EscrowFinish to get applied to a validated ledger
482+ this .scanForResult (
483+ () -> this .getValidatedTransaction (cancelResult .transactionResult ().hash (), EscrowCancel .class )
484+ );
485+
486+ /////////////////////
487+ // Ensure that the funds were released to the receiver.
488+ this .scanForResult (
489+ () -> this .getValidatedAccountInfo (senderKeyPair .publicKey ().deriveAddress ()),
490+ infoResult -> infoResult .accountData ().balance ().equals (
491+ preEscrowFinishSenderAccountInfo .accountData ().balance ()
492+ .plus (escrowCreate .amount ())
493+ .minus (feeResult .drops ().openLedgerFee ()))
494+ && infoResult .accountData ().balance ().equals (XrpCurrencyAmount .ofDrops (999999980 ))
495+ );
496+ }
497+
272498 @ Test
273499 public void createAndFinishCryptoConditionBasedEscrow () throws JsonRpcClientErrorException , JsonProcessingException {
274500 //////////////////////
0 commit comments