xrpl 5.0.0 → 5.1.0-batch.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1831,28 +1831,52 @@ function multiSigningData(transaction, signingAccount, opts = {
1831
1831
  }
1832
1832
  exports.multiSigningData = multiSigningData;
1833
1833
  /**
1834
- * Serialize a signingClaim
1834
+ * Serialize an XLS-56 Batch V1_1 signing payload:
1835
+ * HashPrefix.batch | account | sequence | flags | txIDCount | txIDs[]
1836
+ * [ | batchAccount [ | signerAccount ] ]
1835
1837
  *
1836
1838
  * @param batch A Batch object to serialize.
1837
1839
  * @returns the serialized object with appropriate prefix
1838
1840
  */
1839
1841
  function signingBatchData(batch) {
1842
+ if (batch.account == null) {
1843
+ throw Error('No field `account`');
1844
+ }
1845
+ if (batch.sequence == null) {
1846
+ throw Error('No field `sequence`');
1847
+ }
1840
1848
  if (batch.flags == null) {
1841
- throw Error("No field `flags'");
1849
+ throw Error('No field `flags`');
1842
1850
  }
1843
1851
  if (batch.txIDs == null) {
1844
1852
  throw Error('No field `txIDs`');
1845
1853
  }
1846
1854
  const prefix = hash_prefixes_1.HashPrefix.batch;
1855
+ const account = types_1.coreTypes.AccountID.from(batch.account).toBytes();
1856
+ const sequence = types_1.coreTypes.UInt32.from(batch.sequence).toBytes();
1847
1857
  const flags = types_1.coreTypes.UInt32.from(batch.flags).toBytes();
1848
1858
  const txIDsLength = types_1.coreTypes.UInt32.from(batch.txIDs.length).toBytes();
1849
1859
  const bytesList = new binary_serializer_1.BytesList();
1850
1860
  bytesList.put(prefix);
1861
+ bytesList.put(account);
1862
+ bytesList.put(sequence);
1851
1863
  bytesList.put(flags);
1852
1864
  bytesList.put(txIDsLength);
1853
1865
  batch.txIDs.forEach((txID) => {
1854
1866
  bytesList.put(types_1.coreTypes.Hash256.from(txID).toBytes());
1855
1867
  });
1868
+ if (batch.batchAccount != null) {
1869
+ bytesList.put(types_1.coreTypes.AccountID.from(batch.batchAccount).toBytes());
1870
+ }
1871
+ // The wire format is positional, so `signerAccount` must follow `batchAccount`.
1872
+ // Reject `signerAccount` without `batchAccount` to avoid binding the signature
1873
+ // to the wrong account.
1874
+ if (batch.signerAccount != null) {
1875
+ if (batch.batchAccount == null) {
1876
+ throw Error('Field `signerAccount` requires `batchAccount`');
1877
+ }
1878
+ bytesList.put(types_1.coreTypes.AccountID.from(batch.signerAccount).toBytes());
1879
+ }
1856
1880
  return bytesList.toBytes();
1857
1881
  }
1858
1882
  exports.signingBatchData = signingBatchData;
@@ -6620,6 +6644,14 @@ function constructBatchSignerObject(batchAccount, wallet, signature, multisignAd
6620
6644
  }
6621
6645
  return batchSigner;
6622
6646
  }
6647
+ function getBatchSeqValue(transaction) {
6648
+ var _a, _b;
6649
+ const sequence = (_a = transaction.Sequence) !== null && _a !== void 0 ? _a : 0;
6650
+ if (sequence !== 0) {
6651
+ return sequence;
6652
+ }
6653
+ return (_b = transaction.TicketSequence) !== null && _b !== void 0 ? _b : 0;
6654
+ }
6623
6655
  function signMultiBatch(wallet, transaction, opts = {}) {
6624
6656
  var _a;
6625
6657
  const batchAccount = (_a = opts.batchAccount) !== null && _a !== void 0 ? _a : wallet.classicAddress;
@@ -6634,14 +6666,19 @@ function signMultiBatch(wallet, transaction, opts = {}) {
6634
6666
  throw new errors_1.ValidationError('Must be a Batch transaction.');
6635
6667
  }
6636
6668
  (0, models_1.validate)(transaction);
6637
- const involvedAccounts = new Set(transaction.RawTransactions.map((raw) => raw.RawTransaction.Account));
6669
+ const involvedAccounts = new Set();
6670
+ transaction.RawTransactions.forEach((raw) => {
6671
+ involvedAccounts.add(raw.RawTransaction.Account);
6672
+ const counterparty = raw.RawTransaction
6673
+ .Counterparty;
6674
+ if (typeof counterparty === 'string') {
6675
+ involvedAccounts.add(counterparty);
6676
+ }
6677
+ });
6638
6678
  if (!involvedAccounts.has(batchAccount)) {
6639
6679
  throw new errors_1.ValidationError('Must be signing for an address submitting a transaction in the Batch.');
6640
6680
  }
6641
- const fieldsToSign = {
6642
- flags: transaction.Flags,
6643
- txIDs: transaction.RawTransactions.map((rawTx) => (0, hashes_1.hashSignedTx)(rawTx.RawTransaction)),
6644
- };
6681
+ const fieldsToSign = Object.assign({ account: transaction.Account, sequence: getBatchSeqValue(transaction), flags: transaction.Flags, txIDs: transaction.RawTransactions.map((rawTx) => (0, hashes_1.hashSignedTx)(rawTx.RawTransaction)), batchAccount }, (multisignAddress ? { signerAccount: multisignAddress } : {}));
6645
6682
  const signature = (0, ripple_keypairs_1.sign)((0, ripple_binary_codec_1.encodeForSigningBatch)(fieldsToSign), wallet.privateKey);
6646
6683
  transaction.BatchSigners = [
6647
6684
  constructBatchSignerObject(batchAccount, wallet, signature, multisignAddress),
@@ -6672,24 +6709,38 @@ function combineBatchSigners(transactions) {
6672
6709
  return (0, ripple_binary_codec_1.encode)(getTransactionWithAllBatchSigners(batchTransactions));
6673
6710
  }
6674
6711
  exports.combineBatchSigners = combineBatchSigners;
6675
- function validateBatchTransactionEquivalence(transactions) {
6676
- const exampleTransaction = JSON.stringify({
6677
- flags: transactions[0].Flags,
6678
- transactionIDs: transactions[0].RawTransactions.map((rawTx) => (0, hashes_1.hashSignedTx)(rawTx.RawTransaction)),
6679
- });
6680
- if (transactions.slice(1).some((tx) => JSON.stringify({
6712
+ function getBatchEquivalenceKey(tx) {
6713
+ return JSON.stringify({
6714
+ account: tx.Account,
6715
+ sequence: getBatchSeqValue(tx),
6681
6716
  flags: tx.Flags,
6682
6717
  transactionIDs: tx.RawTransactions.map((rawTx) => (0, hashes_1.hashSignedTx)(rawTx.RawTransaction)),
6683
- }) !== exampleTransaction)) {
6684
- throw new errors_1.ValidationError('Flags and transaction hashes are not the same for all provided transactions.');
6718
+ });
6719
+ }
6720
+ function validateBatchTransactionEquivalence(transactions) {
6721
+ const exampleTransaction = getBatchEquivalenceKey(transactions[0]);
6722
+ if (transactions
6723
+ .slice(1)
6724
+ .some((tx) => getBatchEquivalenceKey(tx) !== exampleTransaction)) {
6725
+ throw new errors_1.ValidationError('Account, sequence, flags, and transaction hashes must be the same for all provided transactions.');
6685
6726
  }
6686
6727
  }
6687
6728
  function getTransactionWithAllBatchSigners(transactions) {
6729
+ const outerAccount = transactions[0].Account;
6688
6730
  const sortedSigners = transactions
6689
6731
  .flatMap((tx) => { var _a; return (_a = tx.BatchSigners) !== null && _a !== void 0 ? _a : []; })
6690
- .filter((signer) => signer.BatchSigner.Account !== transactions[0].Account)
6732
+ .filter((signer) => signer.BatchSigner.Account !== outerAccount)
6691
6733
  .sort((signer1, signer2) => (0, utils_1.compareSigners)(signer1.BatchSigner, signer2.BatchSigner));
6692
- return Object.assign(Object.assign({}, transactions[0]), { BatchSigners: sortedSigners });
6734
+ const dedupedSigners = [];
6735
+ let lastAccount = '';
6736
+ for (const signer of sortedSigners) {
6737
+ const account = signer.BatchSigner.Account;
6738
+ if (account !== lastAccount) {
6739
+ dedupedSigners.push(signer);
6740
+ lastAccount = account;
6741
+ }
6742
+ }
6743
+ return Object.assign(Object.assign({}, transactions[0]), { BatchSigners: dedupedSigners });
6693
6744
  }
6694
6745
 
6695
6746