Skip to content

Commit 6f7f5cd

Browse files
committed
Remove LoanSet counterparty from Batch.requiredSigners(), since rippled bars Lending and SAV transactions as Batch inners
1 parent 48d5323 commit 6f7f5cd

2 files changed

Lines changed: 4 additions & 85 deletions

File tree

  • xrpl4j-core/src

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

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,18 +149,12 @@ default BatchFlags flags() {
149149
* extra one. xrpl4j's own construction-time validation ({@link #checkBatchSigners()}) enforces only that no
150150
* required signer is missing, deferring the stricter extra-signer check to the server. Each inner contributes:
151151
* <ul>
152-
* <li>its <em>initiator</em> — its {@code Delegate} when one is present, otherwise its {@code Account};</li>
153-
* <li>its {@code Sponsor}, when the inner also carries a {@code SponsorSignature}; and</li>
154-
* <li>a {@code LoanSet}'s {@code Counterparty}, when present.</li>
152+
* <li>its <em>initiator</em> — its {@code Delegate} when one is present, otherwise its {@code Account}; and</li>
153+
* <li>its {@code Sponsor}, when the inner also carries a {@code SponsorSignature}.</li>
155154
* </ul>
156155
* The outer {@link #account()} is excluded throughout, because it authorises its own inner transactions with the
157156
* signature it puts on the Batch itself.
158157
*
159-
* <p>The {@code Counterparty} branch is unreachable today — {@code LoanSet} is the only type carrying that field,
160-
* and rippled currently bars the entire Lending (XLS-66) and Single Asset Vault (XLS-65) families from being Batch
161-
* inners via its {@code kDisabledTxTypes} list. It is modelled anyway so that this derivation matches rippled's the
162-
* moment those families are permitted in Batches.
163-
*
164158
* @return An unmodifiable {@link Set} of {@link Address}es that must sign this Batch, which may be empty when every
165159
* inner transaction belongs to the outer account.
166160
*/
@@ -177,10 +171,6 @@ default Set<Address> requiredSigners() {
177171
if (innerTransaction.sponsorSignature().isPresent()) {
178172
innerTransaction.sponsor().ifPresent(signers::add);
179173
}
180-
// A LoanSet's Counterparty must also sign (currently unreachable; see the Javadoc above).
181-
if (innerTransaction instanceof LoanSet) {
182-
((LoanSet) innerTransaction).counterparty().ifPresent(signers::add);
183-
}
184174
return signers.build();
185175
})
186176
.filter(address -> !address.equals(outerAccount))
@@ -356,9 +346,8 @@ default Batch checkBatchSigners() {
356346
);
357347

358348
// Check 4: When BatchSigners is non-empty, every account required to sign an inner transaction must have a
359-
// corresponding BatchSigner entry. The required-signer set (initiator, sponsor, and — once permitted —
360-
// LoanSet counterparty, with the outer account excluded) is derived by requiredSigners(), which is the single
361-
// source of truth shared with fee computation.
349+
// corresponding BatchSigner entry. The required-signer set (initiator and sponsor, with the outer account
350+
// excluded) is derived by requiredSigners(), which is the single source of truth shared with fee computation.
362351
if (!this.batchSigners().isEmpty()) {
363352
final Set<Address> actualSignerAccounts = this.batchSigners().stream()
364353
.map(wrapper -> wrapper.batchSigner().account())

xrpl4j-core/src/test/java/org/xrpl/xrpl4j/model/transactions/BatchTest.java

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import org.xrpl.xrpl4j.crypto.keys.Seed;
3232
import org.xrpl.xrpl4j.crypto.signing.Signature;
3333
import org.xrpl.xrpl4j.model.flags.BatchFlags;
34-
import org.xrpl.xrpl4j.model.flags.LoanSetFlags;
3534
import org.xrpl.xrpl4j.model.flags.PaymentFlags;
3635
import org.xrpl.xrpl4j.model.flags.SponsorFlags;
3736
import org.xrpl.xrpl4j.model.flags.TransactionFlags;
@@ -517,63 +516,6 @@ void testBatchSignerFromAccountIsNotSufficientWhenDelegateIsSet() {
517516
.hasMessageContaining(delegateAccount.value());
518517
}
519518

520-
@Test
521-
void testBatchSignerRequiredForLoanSetCounterparty() {
522-
// A LoanSet inner transaction'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-
577519
@Test
578520
void testBatchWithOuterSignerAsOnlyInnerAccount() {
579521
// Create inner transactions all from the outer signer account
@@ -1309,18 +1251,6 @@ private Payment createInnerPayment(Address account, Address delegate, UnsignedIn
13091251
.build();
13101252
}
13111253

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-
13241254
private List<RawTransactionWrapper> createInnerTransactions(int count) {
13251255
return IntStream.range(0, count)
13261256
.mapToObj(i -> RawTransactionWrapper.of(

0 commit comments

Comments
 (0)