|
31 | 31 | import org.xrpl.xrpl4j.crypto.keys.Seed; |
32 | 32 | import org.xrpl.xrpl4j.crypto.signing.Signature; |
33 | 33 | import org.xrpl.xrpl4j.model.flags.BatchFlags; |
| 34 | +import org.xrpl.xrpl4j.model.flags.LoanSetFlags; |
34 | 35 | import org.xrpl.xrpl4j.model.flags.PaymentFlags; |
35 | 36 | import org.xrpl.xrpl4j.model.flags.SponsorFlags; |
36 | 37 | import org.xrpl.xrpl4j.model.flags.TransactionFlags; |
@@ -516,6 +517,63 @@ void testBatchSignerFromAccountIsNotSufficientWhenDelegateIsSet() { |
516 | 517 | .hasMessageContaining(delegateAccount.value()); |
517 | 518 | } |
518 | 519 |
|
| 520 | + @Test |
| 521 | + void testBatchSignerRequiredForLoanSetCounterparty() { |
| 522 | + // A LoanSet inner's Counterparty must also sign the Batch (in addition to the LoanSet Account). |
| 523 | + Address innerAccount = Seed.ed25519Seed().deriveKeyPair().publicKey().deriveAddress(); |
| 524 | + Address counterpartyAccount = Seed.ed25519Seed().deriveKeyPair().publicKey().deriveAddress(); |
| 525 | + PublicKey innerKey = Seed.ed25519Seed().deriveKeyPair().publicKey(); |
| 526 | + PublicKey counterpartyKey = Seed.ed25519Seed().deriveKeyPair().publicKey(); |
| 527 | + |
| 528 | + List<RawTransactionWrapper> transactions = Lists.newArrayList( |
| 529 | + RawTransactionWrapper.of(createInnerLoanSet(innerAccount, counterpartyAccount, UnsignedInteger.ONE)), |
| 530 | + RawTransactionWrapper.of(createInnerPayment(ACCOUNT, UnsignedInteger.valueOf(2))) |
| 531 | + ); |
| 532 | + |
| 533 | + // Should fail because BatchSigners is missing a signature from the Counterparty. |
| 534 | + assertThatThrownBy(() -> Batch.builder() |
| 535 | + .account(ACCOUNT) |
| 536 | + .fee(XrpCurrencyAmount.ofDrops(100)) |
| 537 | + .sequence(UnsignedInteger.ONE) |
| 538 | + .flags(BatchFlags.ALL_OR_NOTHING) |
| 539 | + .rawTransactions(transactions) |
| 540 | + .batchSigners(Lists.newArrayList( |
| 541 | + BatchSignerWrapper.of(BatchSigner.builder() |
| 542 | + .account(innerAccount) |
| 543 | + .signingPublicKey(innerKey) |
| 544 | + .transactionSignature(Signature.fromBase16("00112233")) |
| 545 | + .build() |
| 546 | + ))) |
| 547 | + .build() |
| 548 | + ).isInstanceOf(IllegalArgumentException.class) |
| 549 | + .hasMessageContaining("BatchSigners must contain signatures from all accounts with inner transactions") |
| 550 | + .hasMessageContaining(counterpartyAccount.value()); |
| 551 | + |
| 552 | + // Should succeed once BatchSigners includes both the Account and the Counterparty. |
| 553 | + Batch batch = Batch.builder() |
| 554 | + .account(ACCOUNT) |
| 555 | + .fee(XrpCurrencyAmount.ofDrops(100)) |
| 556 | + .sequence(UnsignedInteger.ONE) |
| 557 | + .flags(BatchFlags.ALL_OR_NOTHING) |
| 558 | + .rawTransactions(transactions) |
| 559 | + .batchSigners(Lists.newArrayList( |
| 560 | + BatchSignerWrapper.of(BatchSigner.builder() |
| 561 | + .account(innerAccount) |
| 562 | + .signingPublicKey(innerKey) |
| 563 | + .transactionSignature(Signature.fromBase16("00112233")) |
| 564 | + .build() |
| 565 | + ), |
| 566 | + BatchSignerWrapper.of(BatchSigner.builder() |
| 567 | + .account(counterpartyAccount) |
| 568 | + .signingPublicKey(counterpartyKey) |
| 569 | + .transactionSignature(Signature.fromBase16("44556677")) |
| 570 | + .build() |
| 571 | + ))) |
| 572 | + .build(); |
| 573 | + |
| 574 | + assertThat(batch.batchSigners()).hasSize(2); |
| 575 | + } |
| 576 | + |
519 | 577 | @Test |
520 | 578 | void testBatchWithOuterSignerAsOnlyInnerAccount() { |
521 | 579 | // Create inner transactions all from the outer signer account |
@@ -1251,6 +1309,18 @@ private Payment createInnerPayment(Address account, Address delegate, UnsignedIn |
1251 | 1309 | .build(); |
1252 | 1310 | } |
1253 | 1311 |
|
| 1312 | + private LoanSet createInnerLoanSet(Address account, Address counterparty, UnsignedInteger sequence) { |
| 1313 | + return LoanSet.builder() |
| 1314 | + .account(account) |
| 1315 | + .counterparty(counterparty) |
| 1316 | + .fee(XrpCurrencyAmount.ofDrops(0)) |
| 1317 | + .sequence(sequence) |
| 1318 | + .flags(LoanSetFlags.of(TransactionFlags.INNER_BATCH_TXN.getValue())) |
| 1319 | + .loanBrokerId(Hash256.of("C031EFE677CDEF1C5F43475B374A16F990EE184F76015CB7548D34B500F72BFB")) |
| 1320 | + .principalRequested(Amount.of("1000000")) |
| 1321 | + .build(); |
| 1322 | + } |
| 1323 | + |
1254 | 1324 | private List<RawTransactionWrapper> createInnerTransactions(int count) { |
1255 | 1325 | return IntStream.range(0, count) |
1256 | 1326 | .mapToObj(i -> RawTransactionWrapper.of( |
|
0 commit comments