From 4803cdce566c10cc6bd4fc696f0ff56fbe883c49 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Fri, 3 May 2024 14:08:56 -0400 Subject: [PATCH 01/73] improve scripts --- packages/xrpl/tools/createValidateTests.js | 6 +++--- packages/xrpl/tools/generateModels.js | 17 ++++++++--------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/xrpl/tools/createValidateTests.js b/packages/xrpl/tools/createValidateTests.js index f88e5da114..d51e883dcc 100644 --- a/packages/xrpl/tools/createValidateTests.js +++ b/packages/xrpl/tools/createValidateTests.js @@ -11,7 +11,7 @@ function getTx(txName) { .filter((tx) => tx.json.TransactionType === txName) .map((tx) => tx.json) if (validTxs.length == 0) { - throw new Error(`Must have ripple-binary-codec fixture for ${txName}`) + return '{ /* TODO: add sample transaction */ }' } const validTx = validTxs[0] delete validTx.TxnSignature @@ -74,7 +74,7 @@ function getInvalidValue(paramTypes) { } else if (paramType == 'XChainBridge') { return JSON.stringify({ XChainDoor: 'test' }) } else { - throw Error(`${paramType} not supported yet`) + return '/*TODO*/' } } @@ -86,7 +86,7 @@ function getInvalidValue(paramTypes) { } else if (JSON.stringify(simplifiedParamTypes) === '["number","string"]') { return JSON.stringify({ currency: 'ETH' }) } else { - throw Error(`${simplifiedParamTypes} not supported yet`) + return '/*TODO*/' } } diff --git a/packages/xrpl/tools/generateModels.js b/packages/xrpl/tools/generateModels.js index cd089dfaca..57148ed3b0 100644 --- a/packages/xrpl/tools/generateModels.js +++ b/packages/xrpl/tools/generateModels.js @@ -49,10 +49,10 @@ function processRippledSource(folder) { ), ) const transactionMatch = jsTransactionFile.match( - /export type Transaction =([| \nA-Za-z]+)\nexport/, + /export type SubmittableTransaction =([| \nA-Za-z]+)\n\/\*\*/, )[0] const existingLibraryTxs = transactionMatch - .replace('\n\nexport', '') + .replace('\n\n/**', '') .split('\n | ') .filter((value) => !value.includes('export type')) .map((value) => value.trim()) @@ -248,10 +248,11 @@ ${validationImportLine}` ) const validateTests = createValidateTests(tx) - fs.writeFileSync( - path.join(path.dirname(__filename), `../test/models/${tx}.test.ts`), - validateTests, - ) + if (validateTests !== '') + fs.writeFileSync( + path.join(path.dirname(__filename), `../test/models/${tx}.test.ts`), + validateTests, + ) updateTransactionFile(transactionMatch, tx) @@ -259,9 +260,7 @@ ${validationImportLine}` console.log(`Added ${tx}`) }) - console.log( - 'Future steps: Adding docstrings to the models and adding integration tests', - ) + // TODO: add docstrings to the models and add integration tests } if (require.main === module) { From 84c89000b756598a8c6aa013ba2420517b579e30 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 7 May 2024 17:09:28 -0400 Subject: [PATCH 02/73] Update settings.json --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5dc2e1cf8e..ef2c734c23 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -39,7 +39,7 @@ "enable": true }, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, From 25ccc09e5136becb46322e0dbc869b9a69e3a794 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 10:40:37 -0400 Subject: [PATCH 03/73] update file locations after refactor --- packages/xrpl/tools/generateModels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/xrpl/tools/generateModels.js b/packages/xrpl/tools/generateModels.js index 57148ed3b0..dca58317dd 100644 --- a/packages/xrpl/tools/generateModels.js +++ b/packages/xrpl/tools/generateModels.js @@ -15,7 +15,7 @@ let jsTransactionFile function processRippledSource(folder) { const sfieldCpp = readFile( - path.join(folder, 'src/ripple/protocol/impl/SField.cpp'), + path.join(folder, 'src/libxrpl/protocol/SField.cpp'), ) const sfieldHits = sfieldCpp.match( /^ *CONSTRUCT_[^\_]+_SFIELD *\( *[^,\n]*,[ \n]*"([^\"\n ]+)"[ \n]*,[ \n]*([^, \n]+)[ \n]*,[ \n]*([0-9]+)(,.*?(notSigning))?/gm, @@ -29,7 +29,7 @@ function processRippledSource(folder) { } const txFormatsCpp = readFile( - path.join(folder, 'src/ripple/protocol/impl/TxFormats.cpp'), + path.join(folder, 'src/libxrpl/protocol/TxFormats.cpp'), ) const txFormatsHits = txFormatsCpp.match( /^ *add\(jss::([^\"\n, ]+),[ \n]*tt[A-Z_]+,[ \n]*{[ \n]*(({sf[A-Za-z0-9]+, soe(OPTIONAL|REQUIRED|DEFAULT)},[ \n]+)*)},[ \n]*[pseudocC]+ommonFields\);/gm, From 75978078a0b6f6939f311ab600f5bfdb51f8ced2 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 10:45:08 -0400 Subject: [PATCH 04/73] add LedgerStateFix --- .../src/models/transactions/LedgerStateFix.ts | 33 +++++++++ .../xrpl/src/models/transactions/index.ts | 1 + .../src/models/transactions/transaction.ts | 9 +++ .../xrpl/test/models/LedgerStateFix.test.ts | 71 +++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 packages/xrpl/src/models/transactions/LedgerStateFix.ts create mode 100644 packages/xrpl/test/models/LedgerStateFix.test.ts diff --git a/packages/xrpl/src/models/transactions/LedgerStateFix.ts b/packages/xrpl/src/models/transactions/LedgerStateFix.ts new file mode 100644 index 0000000000..4ef7fd7f98 --- /dev/null +++ b/packages/xrpl/src/models/transactions/LedgerStateFix.ts @@ -0,0 +1,33 @@ +import { + BaseTransaction, + isNumber, + isString, + validateBaseTransaction, + validateOptionalField, + validateRequiredField, +} from './common' + +/** + * @category Transaction Models + */ +export interface LedgerStateFix extends BaseTransaction { + TransactionType: 'LedgerStateFix' + + LedgerFixType: number + + Owner?: string +} + +/** + * Verify the form and type of a LedgerStateFix at runtime. + * + * @param tx - A LedgerStateFix Transaction. + * @throws When the LedgerStateFix is malformed. + */ +export function validateLedgerStateFix(tx: Record): void { + validateBaseTransaction(tx) + + validateRequiredField(tx, 'LedgerFixType', isNumber) + + validateOptionalField(tx, 'Owner', isString) +} diff --git a/packages/xrpl/src/models/transactions/index.ts b/packages/xrpl/src/models/transactions/index.ts index c7a8120758..3c4c487c9a 100644 --- a/packages/xrpl/src/models/transactions/index.ts +++ b/packages/xrpl/src/models/transactions/index.ts @@ -86,3 +86,4 @@ export { XChainModifyBridgeFlags, XChainModifyBridgeFlagsInterface, } from './XChainModifyBridge' +export { LedgerStateFix } from './LedgerStateFix' diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index 0ddc719539..dfbe1050f4 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -90,6 +90,10 @@ import { XChainModifyBridge, validateXChainModifyBridge, } from './XChainModifyBridge' +import { + LedgerStateFix, + validateLedgerStateFix, +} from './LedgerStateFix' /** * Transactions that can be submitted by clients @@ -115,6 +119,7 @@ export type SubmittableTransaction = | EscrowCancel | EscrowCreate | EscrowFinish + | LedgerStateFix | NFTokenAcceptOffer | NFTokenBurn | NFTokenCancelOffer @@ -306,6 +311,10 @@ export function validate(transaction: Record): void { validateEscrowFinish(tx) break + case 'LedgerStateFix': + validateLedgerStateFix(tx) + break + case 'NFTokenAcceptOffer': validateNFTokenAcceptOffer(tx) break diff --git a/packages/xrpl/test/models/LedgerStateFix.test.ts b/packages/xrpl/test/models/LedgerStateFix.test.ts new file mode 100644 index 0000000000..e8b1eb2917 --- /dev/null +++ b/packages/xrpl/test/models/LedgerStateFix.test.ts @@ -0,0 +1,71 @@ +import { assert } from 'chai' + +import { validate, ValidationError } from '../../src' +import { validateLedgerStateFix } from '../../src/models/transactions/LedgerStateFix' + +/** + * LedgerStateFix Transaction Verification Testing. + * + * Providing runtime verification testing for each specific transaction type. + */ +describe('LedgerStateFix', function () { + let tx + + beforeEach(function () { + tx = { + TransactionType: 'LedgerStateFix', + LedgerFixType: 1, + Owner: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', + } as any + }) + + it('verifies valid LedgerStateFix', function () { + assert.doesNotThrow(() => validateLedgerStateFix(tx)) + assert.doesNotThrow(() => validate(tx)) + }) + + it('throws w/ missing LedgerFixType', function () { + delete tx.LedgerFixType + + assert.throws( + () => validateLedgerStateFix(tx), + ValidationError, + 'LedgerStateFix: missing field LedgerFixType', + ) + assert.throws( + () => validate(tx), + ValidationError, + 'LedgerStateFix: missing field LedgerFixType', + ) + }) + + it('throws w/ invalid LedgerFixType', function () { + tx.LedgerFixType = 'number' + + assert.throws( + () => validateLedgerStateFix(tx), + ValidationError, + 'LedgerStateFix: invalid field LedgerFixType', + ) + assert.throws( + () => validate(tx), + ValidationError, + 'LedgerStateFix: invalid field LedgerFixType', + ) + }) + + it('throws w/ invalid Owner', function () { + tx.Owner = 123 + + assert.throws( + () => validateLedgerStateFix(tx), + ValidationError, + 'LedgerStateFix: invalid field Owner', + ) + assert.throws( + () => validate(tx), + ValidationError, + 'LedgerStateFix: invalid field Owner', + ) + }) +}) From ef4ab32de8850fbf7f706049e819c79f762e79fd Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 15:06:16 -0400 Subject: [PATCH 05/73] add Batch --- .../xrpl/src/models/transactions/Batch.ts | 81 +++++++++++++++ .../xrpl/src/models/transactions/common.ts | 30 +++--- .../xrpl/src/models/transactions/index.ts | 1 + .../src/models/transactions/transaction.ts | 11 ++- packages/xrpl/test/models/Batch.test.ts | 98 +++++++++++++++++++ 5 files changed, 206 insertions(+), 15 deletions(-) create mode 100644 packages/xrpl/src/models/transactions/Batch.ts create mode 100644 packages/xrpl/test/models/Batch.test.ts diff --git a/packages/xrpl/src/models/transactions/Batch.ts b/packages/xrpl/src/models/transactions/Batch.ts new file mode 100644 index 0000000000..828e7a6953 --- /dev/null +++ b/packages/xrpl/src/models/transactions/Batch.ts @@ -0,0 +1,81 @@ +import { Signer } from '../common' + +import { + BaseTransaction, + isString, + validateBaseTransaction, + validateOptionalField, + validateRequiredField, +} from './common' +import type { Transaction } from './transaction' + +export interface BatchSigner { + Account: string + + SigningPubKey?: string + + TxnSignature?: string + + Signers?: Signer[] +} + +/** + * @category Transaction Models + */ +export interface Batch extends BaseTransaction { + TransactionType: 'Batch' + + BatchSigners?: BatchSigner[] + + RawTransactions: Transaction & { + BatchTxn: { + OuterAccount: string + + Sequence?: number + + TicketSequence?: number + + BatchIndex: number + } + } + + TxIDs: string[] +} + +/** + * Verify the form and type of a Batch at runtime. + * + * @param tx - A Batch Transaction. + * @throws When the Batch is malformed. + */ +export function validateBatch(tx: Record): void { + validateBaseTransaction(tx) + + validateOptionalField(tx, 'BatchSigners', (field) => { + if (!(typeof field === 'object')) { + return false + } + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above + const fieldObject = field as Record + validateRequiredField( + fieldObject, + 'Account', + isString, + 'BatchSigners.Account', + ) + validateOptionalField( + fieldObject, + 'SigningPubKey', + isString, + 'BatchSigners.SigningPubKey', + ) + validateOptionalField( + fieldObject, + 'TxnSignature', + isString, + 'BatchSigners.TxnSignature', + ) + + return true + }) +} diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index 5af72d038a..e61a7f6bcd 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -169,25 +169,29 @@ export function isXChainBridge(input: unknown): input is XChainBridge { /** * Verify the form and type of a required type for a transaction at runtime. * - * @param tx - The transaction input to check the form and type of. - * @param paramName - The name of the transaction parameter. + * @param tx - The object input to check the form and type of. + * @param param - The object parameter. * @param checkValidity - The function to use to check the type. + * @param paramName - The name of the object parameter (if different from the parameter). * @throws */ +// eslint-disable-next-line max-params -- helper function export function validateRequiredField( tx: Record, - paramName: string, + param: string, checkValidity: (inp: unknown) => boolean, + paramName: string | undefined = undefined, ): void { - if (tx[paramName] == null) { + const paramNameStr = paramName ?? param + if (tx[param] == null) { throw new ValidationError( - `${tx.TransactionType}: missing field ${paramName}`, + `${tx.TransactionType}: missing field ${paramNameStr}`, ) } - if (!checkValidity(tx[paramName])) { + if (!checkValidity(tx[param])) { throw new ValidationError( - `${tx.TransactionType}: invalid field ${paramName}`, + `${tx.TransactionType}: invalid field ${paramNameStr}`, ) } } @@ -196,18 +200,22 @@ export function validateRequiredField( * Verify the form and type of an optional type for a transaction at runtime. * * @param tx - The transaction input to check the form and type of. - * @param paramName - The name of the transaction parameter. + * @param param - The object parameter. * @param checkValidity - The function to use to check the type. + * @param paramName - The name of the object parameter (if different from the parameter). * @throws */ +// eslint-disable-next-line max-params -- helper function export function validateOptionalField( tx: Record, - paramName: string, + param: string, checkValidity: (inp: unknown) => boolean, + paramName: string | undefined = undefined, ): void { - if (tx[paramName] !== undefined && !checkValidity(tx[paramName])) { + const paramNameStr = paramName ?? param + if (tx[param] !== undefined && !checkValidity(tx[param])) { throw new ValidationError( - `${tx.TransactionType}: invalid field ${paramName}`, + `${tx.TransactionType}: invalid field ${paramNameStr}`, ) } } diff --git a/packages/xrpl/src/models/transactions/index.ts b/packages/xrpl/src/models/transactions/index.ts index 3c4c487c9a..8f6bf159c8 100644 --- a/packages/xrpl/src/models/transactions/index.ts +++ b/packages/xrpl/src/models/transactions/index.ts @@ -86,4 +86,5 @@ export { XChainModifyBridgeFlags, XChainModifyBridgeFlagsInterface, } from './XChainModifyBridge' +export { Batch } from './batch' export { LedgerStateFix } from './LedgerStateFix' diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index dfbe1050f4..a5ae1fb2ec 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -14,6 +14,7 @@ import { AMMDelete, validateAMMDelete } from './AMMDelete' import { AMMDeposit, validateAMMDeposit } from './AMMDeposit' import { AMMVote, validateAMMVote } from './AMMVote' import { AMMWithdraw, validateAMMWithdraw } from './AMMWithdraw' +import { Batch, validateBatch } from './batch' import { CheckCancel, validateCheckCancel } from './checkCancel' import { CheckCash, validateCheckCash } from './checkCash' import { CheckCreate, validateCheckCreate } from './checkCreate' @@ -26,6 +27,7 @@ import { EnableAmendment } from './enableAmendment' import { EscrowCancel, validateEscrowCancel } from './escrowCancel' import { EscrowCreate, validateEscrowCreate } from './escrowCreate' import { EscrowFinish, validateEscrowFinish } from './escrowFinish' +import { LedgerStateFix, validateLedgerStateFix } from './LedgerStateFix' import { TransactionMetadata } from './metadata' import { NFTokenAcceptOffer, @@ -90,10 +92,6 @@ import { XChainModifyBridge, validateXChainModifyBridge, } from './XChainModifyBridge' -import { - LedgerStateFix, - validateLedgerStateFix, -} from './LedgerStateFix' /** * Transactions that can be submitted by clients @@ -109,6 +107,7 @@ export type SubmittableTransaction = | AMMWithdraw | AccountDelete | AccountSet + | Batch | CheckCancel | CheckCash | CheckCreate @@ -271,6 +270,10 @@ export function validate(transaction: Record): void { validateAccountSet(tx) break + case 'Batch': + validateBatch(tx) + break + case 'CheckCancel': validateCheckCancel(tx) break diff --git a/packages/xrpl/test/models/Batch.test.ts b/packages/xrpl/test/models/Batch.test.ts new file mode 100644 index 0000000000..e8f58a18f2 --- /dev/null +++ b/packages/xrpl/test/models/Batch.test.ts @@ -0,0 +1,98 @@ +import { assert } from 'chai' + +import { validate, ValidationError } from '../../src' +import { validateBatch } from '../../src/models/transactions/batch' + +/** + * Batch Transaction Verification Testing. + * + * Providing runtime verification testing for each specific transaction type. + */ +describe('Batch', function () { + let tx + + beforeEach(function () { + tx = { + /* TODO: add sample transaction */ + } as any + }) + + it('verifies valid Batch', function () { + assert.doesNotThrow(() => validateBatch(tx)) + assert.doesNotThrow(() => validate(tx)) + }) + + // it('throws w/ invalid BatchSigners', function () { + // tx.BatchSigners = + // /* TODO */ + + // assert.throws( + // () => validateBatch(tx), + // ValidationError, + // 'Batch: invalid field BatchSigners', + // ) + // assert.throws( + // () => validate(tx), + // ValidationError, + // 'Batch: invalid field BatchSigners', + // ) + // }) + + it('throws w/ missing RawTransactions', function () { + delete tx.RawTransactions + + assert.throws( + () => validateBatch(tx), + ValidationError, + 'Batch: missing field RawTransactions', + ) + assert.throws( + () => validate(tx), + ValidationError, + 'Batch: missing field RawTransactions', + ) + }) + + // it('throws w/ invalid RawTransactions', function () { + // tx.RawTransactions = assert.throws( + // () => validateBatch(tx), + // ValidationError, + // 'Batch: invalid field RawTransactions', + // ) + // assert.throws( + // () => validate(tx), + // ValidationError, + // 'Batch: invalid field RawTransactions', + // ) + // }) + + it('throws w/ missing TxIDs', function () { + delete tx.TxIDs + + assert.throws( + () => validateBatch(tx), + ValidationError, + 'Batch: missing field TxIDs', + ) + assert.throws( + () => validate(tx), + ValidationError, + 'Batch: missing field TxIDs', + ) + }) + + // it('throws w/ invalid TxIDs', function () { + // tx.TxIDs = ['hi'] + + // assert.throws( + // () => validateBatch(tx), + // ValidationError, + // 'Batch: invalid field TxIDs', + // ) + // assert.throws( + // () => validate(tx), + // ValidationError, + // 'Batch: invalid field TxIDs', + // ) + // }) +}) From 762e57e49e4f638670f18a244e35156a483916e5 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 15:30:12 -0400 Subject: [PATCH 06/73] add BatchTxn autofill --- packages/xrpl/src/client/index.ts | 35 ++----- .../xrpl/src/models/transactions/Batch.ts | 16 ++-- packages/xrpl/src/sugar/autofill.ts | 92 +++++++++++++++++-- 3 files changed, 100 insertions(+), 43 deletions(-) diff --git a/packages/xrpl/src/client/index.ts b/packages/xrpl/src/client/index.ts index 722b169f2a..5cd3947c80 100644 --- a/packages/xrpl/src/client/index.ts +++ b/packages/xrpl/src/client/index.ts @@ -62,6 +62,8 @@ import { setLatestValidatedLedgerSequence, checkAccountDeleteBlockers, txNeedsNetworkID, + autofillBatchTxn, + handleDeliverMax, } from '../sugar/autofill' import { formatBalances } from '../sugar/balances' import { @@ -657,7 +659,6 @@ class Client extends EventEmitter { * @throws ValidationError If Amount and DeliverMax fields are not identical in a Payment Transaction */ - // eslint-disable-next-line complexity -- handling Payment transaction API v2 requires more logic public async autofill( transaction: T, signersCount?: number, @@ -683,33 +684,11 @@ class Client extends EventEmitter { if (tx.TransactionType === 'AccountDelete') { promises.push(checkAccountDeleteBlockers(this, tx)) } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property - // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level - if (tx.TransactionType === 'Payment' && tx.DeliverMax != null) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- This is a valid null check for Amount - if (tx.Amount == null) { - // If only DeliverMax is provided, use it to populate the Amount field - // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property - // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- DeliverMax is a known RPC-level property - tx.Amount = tx.DeliverMax - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property - // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- This is a valid null check for Amount - if (tx.Amount != null && tx.Amount !== tx.DeliverMax) { - return Promise.reject( - new ValidationError( - 'PaymentTransaction: Amount and DeliverMax fields must be identical when both are provided', - ), - ) - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property - // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level - delete tx.DeliverMax + if (tx.TransactionType === 'Batch') { + promises.push(autofillBatchTxn(this, tx)) + } + if (tx.TransactionType === 'Payment') { + handleDeliverMax(tx) } return Promise.all(promises).then(() => tx) diff --git a/packages/xrpl/src/models/transactions/Batch.ts b/packages/xrpl/src/models/transactions/Batch.ts index 828e7a6953..cc9ceb78a6 100644 --- a/packages/xrpl/src/models/transactions/Batch.ts +++ b/packages/xrpl/src/models/transactions/Batch.ts @@ -27,17 +27,19 @@ export interface Batch extends BaseTransaction { BatchSigners?: BatchSigner[] - RawTransactions: Transaction & { - BatchTxn: { - OuterAccount: string + RawTransactions: Array< + Transaction & { + BatchTxn: { + OuterAccount: string - Sequence?: number + Sequence?: number - TicketSequence?: number + TicketSequence?: number - BatchIndex: number + BatchIndex: number + } } - } + > TxIDs: string[] } diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index ca0757611d..252d981d94 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -1,10 +1,11 @@ +/* eslint-disable max-lines - lots of helper functions needed for autofill */ import BigNumber from 'bignumber.js' import { xAddressToClassicAddress, isValidXAddress } from 'ripple-address-codec' import { type Client } from '..' import { ValidationError, XrplError } from '../errors' import { AccountInfoRequest, AccountObjectsRequest } from '../models/methods' -import { Transaction } from '../models/transactions' +import { Batch, Payment, Transaction } from '../models/transactions' import { xrpToDrops } from '../utils' import getFeeXrp from './getFeeXrp' @@ -207,6 +208,20 @@ function convertToClassicAddress(tx: Transaction, fieldName: string): void { } } +// Helper function to get the next valid sequence number for an account. +async function getNextValidSequenceNumber( + client: Client, + account: string, +): Promise { + const request: AccountInfoRequest = { + command: 'account_info', + account, + ledger_index: 'current', + } + const data = await client.request(request) + return data.result.account_data.Sequence +} + /** * Sets the next valid sequence number for a transaction. * @@ -219,14 +234,8 @@ export async function setNextValidSequenceNumber( client: Client, tx: Transaction, ): Promise { - const request: AccountInfoRequest = { - command: 'account_info', - account: tx.Account, - ledger_index: 'current', - } - const data = await client.request(request) // eslint-disable-next-line no-param-reassign, require-atomic-updates -- param reassign is safe with no race condition - tx.Sequence = data.result.account_data.Sequence + tx.Sequence = await getNextValidSequenceNumber(client, tx.Account) } /** @@ -359,3 +368,70 @@ export async function checkAccountDeleteBlockers( resolve() }) } +/** + * Replaces Amount with DeliverMax if needed. + * + * @param tx - The transaction object. + * @throws ValidationError if Amount and DeliverMax are both provided but do not match. + */ +export function handleDeliverMax(tx: Payment): void { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property + // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level + if (tx.DeliverMax != null) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed here + if (tx.Amount == null) { + // If only DeliverMax is provided, use it to populate the Amount field + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property + // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, no-param-reassign -- known RPC-level property + tx.Amount = tx.DeliverMax + } + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property + // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed here + if (tx.Amount != null && tx.Amount !== tx.DeliverMax) { + throw new ValidationError( + 'PaymentTransaction: Amount and DeliverMax fields must be identical when both are provided', + ) + } + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property + // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level + // eslint-disable-next-line no-param-reassign -- needed here + delete tx.DeliverMax + } +} + +/** + * Autofills all the relevant `BatchTxn` fields. + * + * @param client - The client object. + * @param tx - The transaction object. + * @returns A promise that resolves with void if there are no blockers, or rejects with an XrplError if there are blockers. + */ +export async function autofillBatchTxn( + client: Client, + tx: Batch, +): Promise { + const accountSequences: Record = {} + let batchIndex = 0 + + for await (const txn of tx.RawTransactions) { + txn.BatchTxn.OuterAccount = tx.Account + if (txn.BatchTxn.TicketSequence != null && txn.BatchTxn.Sequence != null) { + // eslint-disable-next-line max-depth -- okay here + if (txn.Account in accountSequences) { + txn.BatchTxn.Sequence = accountSequences[txn.Account] + accountSequences[txn.Account] += 1 + } else { + const sequence = await getNextValidSequenceNumber(client, txn.Account) + accountSequences[txn.Account] = sequence + 1 + txn.BatchTxn.Sequence = sequence + } + } + txn.BatchTxn.BatchIndex = batchIndex + batchIndex += 1 + } +} From 28bce04212e4ebf9f12c3ca88307e211bcc3e7d1 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 16:32:23 -0400 Subject: [PATCH 07/73] add multi-account signing --- packages/xrpl/src/Wallet/index.ts | 26 ++++++++++++++++++- .../xrpl/src/models/transactions/Batch.ts | 26 +++++++++---------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index c5ce5baca5..9fd16e47d5 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -23,7 +23,7 @@ import { import ECDSA from '../ECDSA' import { ValidationError } from '../errors' -import { Transaction, validate } from '../models/transactions' +import { Batch, Transaction, validate } from '../models/transactions' import { ensureClassicAddress } from '../sugar/utils' import { omitBy } from '../utils/collections' import { hashSignedTx } from '../utils/hashes/hashLedger' @@ -437,6 +437,30 @@ export class Wallet { } } + /** + * Sign a multi-account Batch transaction. + * + * @param this - Wallet instance. + * @param transaction - The Batch transaction to sign + * @returns The signature to include in `BatchSigners`. + */ + public signMultiBatch( + this: Wallet, + transaction: { Flags: number; TxIDs: string[] } | Batch, + ): string { + // TODO: add multisign support + transaction.TxIDs.forEach((txId, index) => { + if (typeof txId !== 'string') { + throw new ValidationError(`TxID #${index} is not a string.`) + } + }) + const fieldsToSign = { + Flags: transaction.Flags, + TxIDs: transaction.TxIDs, + } + return sign(encodeForSigning(fieldsToSign), this.privateKey) + } + /** * Verifies a signed transaction offline. * diff --git a/packages/xrpl/src/models/transactions/Batch.ts b/packages/xrpl/src/models/transactions/Batch.ts index cc9ceb78a6..bd88edeb38 100644 --- a/packages/xrpl/src/models/transactions/Batch.ts +++ b/packages/xrpl/src/models/transactions/Batch.ts @@ -9,6 +9,18 @@ import { } from './common' import type { Transaction } from './transaction' +export type BatchInnerTransaction = Transaction & { + BatchTxn?: { + OuterAccount: string + + Sequence?: number + + TicketSequence?: number + + BatchIndex: number + } +} + export interface BatchSigner { Account: string @@ -27,19 +39,7 @@ export interface Batch extends BaseTransaction { BatchSigners?: BatchSigner[] - RawTransactions: Array< - Transaction & { - BatchTxn: { - OuterAccount: string - - Sequence?: number - - TicketSequence?: number - - BatchIndex: number - } - } - > + RawTransactions: BatchInnerTransaction[] TxIDs: string[] } From f6715327d1e520e1fc67a449548a6a8caaf08457 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 16:56:45 -0400 Subject: [PATCH 08/73] add combine function --- packages/xrpl/src/Wallet/index.ts | 2 +- packages/xrpl/src/Wallet/signer.ts | 105 +++++++++++++++++- .../xrpl/src/models/transactions/Batch.ts | 10 +- packages/xrpl/src/sugar/autofill.ts | 12 +- 4 files changed, 122 insertions(+), 7 deletions(-) diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index 9fd16e47d5..e23e4fad8f 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -448,7 +448,6 @@ export class Wallet { this: Wallet, transaction: { Flags: number; TxIDs: string[] } | Batch, ): string { - // TODO: add multisign support transaction.TxIDs.forEach((txId, index) => { if (typeof txId !== 'string') { throw new ValidationError(`TxID #${index} is not a string.`) @@ -458,6 +457,7 @@ export class Wallet { Flags: transaction.Flags, TxIDs: transaction.TxIDs, } + // TODO: add multisign support return sign(encodeForSigning(fieldsToSign), this.privateKey) } diff --git a/packages/xrpl/src/Wallet/signer.ts b/packages/xrpl/src/Wallet/signer.ts index 126e629cd7..04da21c0ac 100644 --- a/packages/xrpl/src/Wallet/signer.ts +++ b/packages/xrpl/src/Wallet/signer.ts @@ -7,6 +7,7 @@ import { verify } from 'ripple-keypairs' import { ValidationError } from '../errors' import { Signer } from '../models/common' import { Transaction, validate } from '../models/transactions' +import { Batch, BatchSigner, validateBatch } from '../models/transactions/batch' /** * Takes several transactions with Signer fields (in object or blob form) and creates a @@ -55,6 +56,57 @@ function multisign(transactions: Array): string { return encode(getTransactionWithAllSigners(decodedTransactions)) } +/** + * Takes several transactions with BatchSigners fields (in object or blob form) and creates a + * single transaction with all BatchSigners that then gets signed and returned. + * + * @param transactions The transactions to combine `BatchSigners` values on. + * @returns A single signed Transaction which has all BatchSigners from transactions within it. + * @throws ValidationError if: + * - There were no transactions given to sign + * @category Signing + */ +function combineBatchSignatures(transactions: Array): string { + if (transactions.length === 0) { + throw new ValidationError('There were 0 transactions to combine') + } + + const decodedTransactions: Transaction[] = transactions.map( + (txOrBlob: string | Transaction) => { + return getDecodedTransaction(txOrBlob) + }, + ) + + decodedTransactions.forEach((tx) => { + if (tx.TransactionType !== 'Batch') { + throw new ValidationError('TransactionType must be `Batch`.') + } + /* + * This will throw a more clear error for JS users if any of the supplied transactions has incorrect formatting + */ + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type + validateBatch(tx as unknown as Record) + if (tx.Signers == null || tx.Signers.length === 0) { + throw new ValidationError( + "For multisigning all transactions must include a Signers field containing an array of signatures. You may have forgotten to pass the 'forMultisign' parameter when signing.", + ) + } + + if (tx.SigningPubKey !== '') { + throw new ValidationError( + 'SigningPubKey must be an empty string for all transactions when multisigning.', + ) + } + }) + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above + const batchTransactions = decodedTransactions as Batch[] + + validateBatchTransactionEquivalence(batchTransactions) + + return encode(getTransactionWithAllBatchSigners(batchTransactions)) +} + /** * Verifies that the given transaction has a valid signature based on public-key encryption. * @@ -115,6 +167,32 @@ function validateTransactionEquivalence(transactions: Transaction[]): void { } } +/** + * The transactions should all be equal except for the 'Signers' field. + * + * @param transactions - An array of Transactions which are expected to be equal other than 'Signers'. + * @throws ValidationError if the transactions are not equal in any field other than 'Signers'. + */ +function validateBatchTransactionEquivalence(transactions: Batch[]): void { + const exampleTransaction = JSON.stringify({ + Flags: transactions[0].Flags, + TxIDs: transactions[0].TxIDs, + }) + if ( + transactions + .slice(1) + .some( + (tx) => + JSON.stringify({ Flags: tx.Flags, TxIDs: tx.TxIDs }) !== + exampleTransaction, + ) + ) { + throw new ValidationError( + 'Flags and TxIDs is not the same for all provided transactions', + ) + } +} + function getTransactionWithAllSigners( transactions: Transaction[], ): Transaction { @@ -126,6 +204,15 @@ function getTransactionWithAllSigners( return { ...transactions[0], Signers: sortedSigners } } +function getTransactionWithAllBatchSigners(transactions: Batch[]): Transaction { + // Signers must be sorted in the combined transaction - See compareSigners' documentation for more details + const sortedSigners: BatchSigner[] = transactions + .flatMap((tx) => tx.BatchSigners ?? []) + .sort(compareBatchSigners) + + return { ...transactions[0], BatchSigners: sortedSigners } +} + /** * If presented in binary form, the Signers array must be sorted based on * the numeric value of the signer addresses, with the lowest value first. @@ -142,6 +229,22 @@ function compareSigners(left: Signer, right: Signer): number { ) } +/** + * If presented in binary form, the BatchSigners array must be sorted based on + * the numeric value of the signer addresses, with the lowest value first. + * (If submitted as JSON, the submit_multisigned method handles this automatically.) + * https://xrpl.org/multi-signing.html. + * + * @param left - A BatchSigner to compare with. + * @param right - A second BatchSigner to compare with. + * @returns 1 if left \> right, 0 if left = right, -1 if left \< right, and null if left or right are NaN. + */ +function compareBatchSigners(left: BatchSigner, right: BatchSigner): number { + return addressToBigNumber(left.BatchSigner.Account).comparedTo( + addressToBigNumber(right.BatchSigner.Account), + ) +} + const NUM_BITS_IN_HEX = 16 function addressToBigNumber(address: string): BigNumber { @@ -160,4 +263,4 @@ function getDecodedTransaction(txOrBlob: Transaction | string): Transaction { return decode(txOrBlob) as unknown as Transaction } -export { verifySignature, multisign } +export { combineBatchSignatures, verifySignature, multisign } diff --git a/packages/xrpl/src/models/transactions/Batch.ts b/packages/xrpl/src/models/transactions/Batch.ts index bd88edeb38..e341677977 100644 --- a/packages/xrpl/src/models/transactions/Batch.ts +++ b/packages/xrpl/src/models/transactions/Batch.ts @@ -22,13 +22,15 @@ export type BatchInnerTransaction = Transaction & { } export interface BatchSigner { - Account: string + BatchSigner: { + Account: string - SigningPubKey?: string + SigningPubKey?: string - TxnSignature?: string + TxnSignature?: string - Signers?: Signer[] + Signers?: Signer[] + } } /** diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 252d981d94..ea0643dc45 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -1,4 +1,3 @@ -/* eslint-disable max-lines - lots of helper functions needed for autofill */ import BigNumber from 'bignumber.js' import { xAddressToClassicAddress, isValidXAddress } from 'ripple-address-codec' @@ -419,19 +418,30 @@ export async function autofillBatchTxn( let batchIndex = 0 for await (const txn of tx.RawTransactions) { + if (txn.BatchTxn === undefined) { + /* eslint-disable @typescript-eslint/ban-ts-comment -- just for now */ + // @ts-expect-error -- just for now + txn.BatchTxn = {} + } + // @ts-expect-error -- just for now txn.BatchTxn.OuterAccount = tx.Account + // @ts-expect-error -- just for now if (txn.BatchTxn.TicketSequence != null && txn.BatchTxn.Sequence != null) { // eslint-disable-next-line max-depth -- okay here if (txn.Account in accountSequences) { + // @ts-expect-error -- just for now txn.BatchTxn.Sequence = accountSequences[txn.Account] accountSequences[txn.Account] += 1 } else { const sequence = await getNextValidSequenceNumber(client, txn.Account) accountSequences[txn.Account] = sequence + 1 + // @ts-expect-error -- just for now txn.BatchTxn.Sequence = sequence } } + // @ts-expect-error -- just for now txn.BatchTxn.BatchIndex = batchIndex batchIndex += 1 + /* eslint-enable @typescript-eslint/ban-ts-comment -- just for now */ } } From 9643508f35d767c61228710081332b20a22fd545 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 17:09:30 -0400 Subject: [PATCH 09/73] add Batch support to hashing txs --- packages/xrpl/src/utils/hashes/hashLedger.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/xrpl/src/utils/hashes/hashLedger.ts b/packages/xrpl/src/utils/hashes/hashLedger.ts index e9cb9329b6..ec95e1e7d5 100644 --- a/packages/xrpl/src/utils/hashes/hashLedger.ts +++ b/packages/xrpl/src/utils/hashes/hashLedger.ts @@ -82,9 +82,10 @@ export function hashSignedTx(tx: Transaction | string): string { } if ( - txObject.TxnSignature === undefined && - txObject.Signers === undefined && - txObject.SigningPubKey === undefined + !('TxnSignature' in txObject) && + !('Signers' in txObject) && + !('SigningPubKey' in txObject) && + !('BatchTxn' in txObject) ) { throw new ValidationError('The transaction must be signed to hash it.') } From e743ddc61974ace9d8f677420731e0919b54bff7 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 18:51:37 -0400 Subject: [PATCH 10/73] add autofill TxID support --- .../xrpl/src/models/transactions/Batch.ts | 21 +++++---- packages/xrpl/src/sugar/autofill.ts | 46 ++++++++++--------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/packages/xrpl/src/models/transactions/Batch.ts b/packages/xrpl/src/models/transactions/Batch.ts index e341677977..8c3c73d5df 100644 --- a/packages/xrpl/src/models/transactions/Batch.ts +++ b/packages/xrpl/src/models/transactions/Batch.ts @@ -9,16 +9,18 @@ import { } from './common' import type { Transaction } from './transaction' -export type BatchInnerTransaction = Transaction & { - BatchTxn?: { - OuterAccount: string +export interface BatchTxn { + OuterAccount: string - Sequence?: number + Sequence?: number - TicketSequence?: number + TicketSequence?: number - BatchIndex: number - } + BatchIndex: number +} + +export type BatchInnerTransaction = Transaction & { + BatchTxn?: BatchTxn } export interface BatchSigner { @@ -43,7 +45,10 @@ export interface Batch extends BaseTransaction { RawTransactions: BatchInnerTransaction[] - TxIDs: string[] + /** + * Optional because it can be autofilled. + */ + TxIDs?: string[] } /** diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index ea0643dc45..7fdd0904dc 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-lines -- lots of helper functions needed for autofill */ import BigNumber from 'bignumber.js' import { xAddressToClassicAddress, isValidXAddress } from 'ripple-address-codec' @@ -5,7 +6,9 @@ import { type Client } from '..' import { ValidationError, XrplError } from '../errors' import { AccountInfoRequest, AccountObjectsRequest } from '../models/methods' import { Batch, Payment, Transaction } from '../models/transactions' +import { BatchTxn } from '../models/transactions/batch' import { xrpToDrops } from '../utils' +import { hashSignedTx } from '../utils/hashes' import getFeeXrp from './getFeeXrp' @@ -416,32 +419,31 @@ export async function autofillBatchTxn( ): Promise { const accountSequences: Record = {} let batchIndex = 0 + const txIds: string[] = [] for await (const txn of tx.RawTransactions) { - if (txn.BatchTxn === undefined) { - /* eslint-disable @typescript-eslint/ban-ts-comment -- just for now */ - // @ts-expect-error -- just for now - txn.BatchTxn = {} + if (txn.BatchTxn !== undefined) { + continue } - // @ts-expect-error -- just for now - txn.BatchTxn.OuterAccount = tx.Account - // @ts-expect-error -- just for now - if (txn.BatchTxn.TicketSequence != null && txn.BatchTxn.Sequence != null) { - // eslint-disable-next-line max-depth -- okay here - if (txn.Account in accountSequences) { - // @ts-expect-error -- just for now - txn.BatchTxn.Sequence = accountSequences[txn.Account] - accountSequences[txn.Account] += 1 - } else { - const sequence = await getNextValidSequenceNumber(client, txn.Account) - accountSequences[txn.Account] = sequence + 1 - // @ts-expect-error -- just for now - txn.BatchTxn.Sequence = sequence - } + const batchTxn: Partial = {} + batchTxn.OuterAccount = tx.Account + + if (txn.Account in accountSequences) { + batchTxn.Sequence = accountSequences[txn.Account] + accountSequences[txn.Account] += 1 + } else { + const sequence = await getNextValidSequenceNumber(client, txn.Account) + accountSequences[txn.Account] = sequence + 1 + batchTxn.Sequence = sequence } - // @ts-expect-error -- just for now - txn.BatchTxn.BatchIndex = batchIndex + batchTxn.BatchIndex = batchIndex batchIndex += 1 - /* eslint-enable @typescript-eslint/ban-ts-comment -- just for now */ + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above + txn.BatchTxn = batchTxn as BatchTxn + txIds.push(hashSignedTx(txn)) + } + if (tx.TxIDs != null) { + // eslint-disable-next-line no-param-reassign -- okay for autofilling + tx.TxIDs = txIds } } From 826fff85420c27bcfac28dafee3a8d3fe9f7399e Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 19:03:22 -0400 Subject: [PATCH 11/73] better validation --- packages/xrpl/src/models/transactions/Batch.ts | 6 +++++- packages/xrpl/src/models/transactions/common.ts | 10 ++++++++++ packages/xrpl/src/models/transactions/transaction.ts | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/xrpl/src/models/transactions/Batch.ts b/packages/xrpl/src/models/transactions/Batch.ts index 8c3c73d5df..b481efebab 100644 --- a/packages/xrpl/src/models/transactions/Batch.ts +++ b/packages/xrpl/src/models/transactions/Batch.ts @@ -2,6 +2,7 @@ import { Signer } from '../common' import { BaseTransaction, + isObject, isString, validateBaseTransaction, validateOptionalField, @@ -60,8 +61,11 @@ export interface Batch extends BaseTransaction { export function validateBatch(tx: Record): void { validateBaseTransaction(tx) + validateRequiredField(tx, 'RawTransactions', isObject) + // Full validation of each `RawTransaction` object is done in `validate` to avoid dependency cycles + validateOptionalField(tx, 'BatchSigners', (field) => { - if (!(typeof field === 'object')) { + if (!isObject(field)) { return false } // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index e61a7f6bcd..fda5ca1fee 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -164,6 +164,16 @@ export function isXChainBridge(input: unknown): input is XChainBridge { ) } +/** + * Verify the form and type of an Object at runtime. + * + * @param input - The object to check the form and type of. + * @returns Whether the Object is properly formed. + */ +export function isObject(input: unknown): input is object { + return typeof input === 'object' +} + /* eslint-disable @typescript-eslint/restrict-template-expressions -- tx.TransactionType is checked before any calls */ /** diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index a5ae1fb2ec..3122da10dd 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -272,6 +272,12 @@ export function validate(transaction: Record): void { case 'Batch': validateBatch(tx) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- okay here + // @ts-expect-error -- already checked + // eslint-disable-next-line @typescript-eslint/no-unsafe-call -- already checked above + tx.RawTransactions.forEach((innerTx: Record) => + validate(innerTx), + ) break case 'CheckCancel': From ab09e38ae588439287a9bc2a6d3d4b0e09dd876a Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 19:08:22 -0400 Subject: [PATCH 12/73] add metadata --- packages/xrpl/src/models/transactions/Batch.ts | 11 +++++++++++ packages/xrpl/src/models/transactions/metadata.ts | 3 +++ 2 files changed, 14 insertions(+) diff --git a/packages/xrpl/src/models/transactions/Batch.ts b/packages/xrpl/src/models/transactions/Batch.ts index b481efebab..8492985320 100644 --- a/packages/xrpl/src/models/transactions/Batch.ts +++ b/packages/xrpl/src/models/transactions/Batch.ts @@ -8,6 +8,7 @@ import { validateOptionalField, validateRequiredField, } from './common' +import type { TransactionMetadataBase } from './metadata' import type { Transaction } from './transaction' export interface BatchTxn { @@ -52,6 +53,16 @@ export interface Batch extends BaseTransaction { TxIDs?: string[] } +export interface BatchMetadata extends TransactionMetadataBase { + BatchExecutions: Array<{ + TransactionType: string + + InnerResult: string + + TransactionHash: string + }> +} + /** * Verify the form and type of a Batch at runtime. * diff --git a/packages/xrpl/src/models/transactions/metadata.ts b/packages/xrpl/src/models/transactions/metadata.ts index 3fcaeb54bf..904d2db530 100644 --- a/packages/xrpl/src/models/transactions/metadata.ts +++ b/packages/xrpl/src/models/transactions/metadata.ts @@ -1,5 +1,6 @@ import { Amount } from '../common' +import { Batch, BatchMetadata } from './batch' import { BaseTransaction } from './common' import { NFTokenAcceptOffer, @@ -97,4 +98,6 @@ export type TransactionMetadata = ? NFTokenAcceptOfferMetadata : T extends NFTokenCancelOffer ? NFTokenCancelOfferMetadata + : T extends Batch + ? BatchMetadata : TransactionMetadataBase From a4b55e269cad2f1b870e72ef24fca2710c3ee989 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 19:24:09 -0400 Subject: [PATCH 13/73] update definitions.json --- .../src/enums/definitions.json | 127 +++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/packages/ripple-binary-codec/src/enums/definitions.json b/packages/ripple-binary-codec/src/enums/definitions.json index 797be9ce21..07d56e5b54 100644 --- a/packages/ripple-binary-codec/src/enums/definitions.json +++ b/packages/ripple-binary-codec/src/enums/definitions.json @@ -260,6 +260,16 @@ "type": "UInt8" } ], + [ + "BatchIndex", + { + "nth": 20, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "UInt8" + } + ], [ "LedgerEntryType", { @@ -370,6 +380,16 @@ "type": "UInt16" } ], + [ + "LedgerFixType", + { + "nth": 21, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "UInt16" + } + ], [ "NetworkID", { @@ -1980,6 +2000,16 @@ "type": "Blob" } ], + [ + "InnerResult", + { + "nth": 30, + "isVLEncoded": true, + "isSerialized": true, + "isSigningField": true, + "type": "Blob" + } + ], [ "Account", { @@ -2140,6 +2170,16 @@ "type": "AccountID" } ], + [ + "OuterAccount", + { + "nth": 24, + "isVLEncoded": true, + "isSerialized": true, + "isSigningField": true, + "type": "AccountID" + } + ], [ "Indexes", { @@ -2180,6 +2220,16 @@ "type": "Vector256" } ], + [ + "TxIDs", + { + "nth": 5, + "isVLEncoded": true, + "isSerialized": true, + "isSigningField": true, + "type": "Vector256" + } + ], [ "Paths", { @@ -2550,6 +2600,46 @@ "type": "STObject" } ], + [ + "RawTransaction", + { + "nth": 33, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "STObject" + } + ], + [ + "BatchExecution", + { + "nth": 34, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "STObject" + } + ], + [ + "BatchTxn", + { + "nth": 35, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "STObject" + } + ], + [ + "BatchSigner", + { + "nth": 36, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "STObject" + } + ], [ "Signers", { @@ -2739,6 +2829,36 @@ "isSigningField": true, "type": "STArray" } + ], + [ + "BatchExecutions", + { + "nth": 26, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "STArray" + } + ], + [ + "RawTransactions", + { + "nth": 27, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "STArray" + } + ], + [ + "BatchSigners", + { + "nth": 28, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": false, + "type": "STArray" + } ] ], "TRANSACTION_RESULTS": { @@ -2808,6 +2928,7 @@ "temEMPTY_DID": -254, "temARRAY_EMPTY": -253, "temARRAY_TOO_LARGE": -252, + "temINVALID_BATCH": -251, "tefFAILURE": -199, "tefALREADY": -198, @@ -2830,6 +2951,7 @@ "tefTOO_BIG": -181, "tefNO_TICKET": -180, "tefNFTOKEN_IS_NOT_TRANSFERABLE": -179, + "tefINVALID_LEDGER_FIX_TYPE": -178, "terRETRY": -99, "terFUNDS_SPENT": -98, @@ -2923,7 +3045,8 @@ "tecINVALID_UPDATE_TIME": 188, "tecTOKEN_PAIR_NOT_FOUND": 189, "tecARRAY_EMPTY": 190, - "tecARRAY_TOO_LARGE": 191 + "tecARRAY_TOO_LARGE": 191, + "tecBATCH_FAILURE": 192 }, "TRANSACTION_TYPES": { "Invalid": -1, @@ -2974,6 +3097,8 @@ "DIDDelete": 50, "OracleSet": 51, "OracleDelete": 52, + "LedgerStateFix": 53, + "Batch": 54, "EnableAmendment": 100, "SetFee": 101, "UNLModify": 102 From 7d7acae4f597315da103180623b61f82fbfbca69 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 19:27:08 -0400 Subject: [PATCH 14/73] clean up --- packages/xrpl/src/Wallet/index.ts | 5 +++++ packages/xrpl/src/models/transactions/transaction.ts | 2 ++ packages/xrpl/src/sugar/autofill.ts | 1 + 3 files changed, 8 insertions(+) diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index e23e4fad8f..0e5a293d21 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-lines -- Lots of helper functions needed for signing */ import { HDKey } from '@scure/bip32' import { mnemonicToSeedSync, validateMnemonic } from '@scure/bip39' import { wordlist } from '@scure/bip39/wordlists/english' @@ -443,11 +444,15 @@ export class Wallet { * @param this - Wallet instance. * @param transaction - The Batch transaction to sign * @returns The signature to include in `BatchSigners`. + * @throws ValidationERror if TxIds isn't included. */ public signMultiBatch( this: Wallet, transaction: { Flags: number; TxIDs: string[] } | Batch, ): string { + if (transaction.TxIDs == null) { + throw new ValidationError('Must include TxIDs to sign.') + } transaction.TxIDs.forEach((txId, index) => { if (typeof txId !== 'string') { throw new ValidationError(`TxID #${index} is not a string.`) diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index 3122da10dd..012f5bae69 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -272,6 +272,8 @@ export function validate(transaction: Record): void { case 'Batch': validateBatch(tx) + // This is done here to avoid issues with dependency cycles + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- okay here // @ts-expect-error -- already checked // eslint-disable-next-line @typescript-eslint/no-unsafe-call -- already checked above diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 7fdd0904dc..b8dce15f28 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -423,6 +423,7 @@ export async function autofillBatchTxn( for await (const txn of tx.RawTransactions) { if (txn.BatchTxn !== undefined) { + // eslint-disable-next-line no-continue -- this is fine continue } const batchTxn: Partial = {} From 8fc2600a190748f5daf238e8c5d522a6bcca3b19 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 19:51:04 -0400 Subject: [PATCH 15/73] update binary codec for signing --- packages/ripple-binary-codec/src/binary.ts | 36 ++++++++++++++++++- .../ripple-binary-codec/src/hash-prefixes.ts | 2 ++ packages/ripple-binary-codec/src/index.ts | 11 +++++- packages/xrpl/src/Wallet/index.ts | 6 +++- 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/packages/ripple-binary-codec/src/binary.ts b/packages/ripple-binary-codec/src/binary.ts index 8ca067d966..5e1c8c0c2e 100644 --- a/packages/ripple-binary-codec/src/binary.ts +++ b/packages/ripple-binary-codec/src/binary.ts @@ -1,7 +1,7 @@ /* eslint-disable func-style */ import { bytesToHex } from '@xrplf/isomorphic/utils' -import { coreTypes } from './types' +import { coreTypes, UInt32 } from './types' import { BinaryParser } from './serdes/binary-parser' import { AccountID } from './types/account-id' import { HashPrefix } from './hash-prefixes' @@ -177,11 +177,44 @@ function multiSigningData( }) } +/** + * Interface describing fields required for a Batch signer + */ +interface BatchObject extends JsonObject { + flags: number + txIDs: string[] +} + +/** + * Serialize a signingClaim + * + * @param batch A Batch object to serialize + * @param opts.definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. + * @returns the serialized object with appropriate prefix + */ +function signingBatchData(batch: BatchObject): Uint8Array { + const prefix = HashPrefix.batch + const flags = coreTypes.UInt32.from(batch.flags).toBytes() + const txIDsLength = coreTypes.UInt32.from(batch.txIDs.length).toBytes() + + const bytesList = new BytesList() + + bytesList.put(prefix) + bytesList.put(flags) + bytesList.put(txIDsLength) + batch.txIDs.forEach((txID: string) => { + bytesList.put(coreTypes.Hash256.from(txID).toBytes()) + }) + + return bytesList.toBytes() +} + export { BinaryParser, BinarySerializer, BytesList, ClaimObject, + BatchObject, makeParser, serializeObject, readJSON, @@ -191,4 +224,5 @@ export { binaryToJSON, sha512Half, transactionID, + signingBatchData, } diff --git a/packages/ripple-binary-codec/src/hash-prefixes.ts b/packages/ripple-binary-codec/src/hash-prefixes.ts index 98035167bc..edfa6e97ad 100644 --- a/packages/ripple-binary-codec/src/hash-prefixes.ts +++ b/packages/ripple-binary-codec/src/hash-prefixes.ts @@ -35,6 +35,8 @@ const HashPrefix: Record = { proposal: bytes(0x50525000), // payment channel claim paymentChannelClaim: bytes(0x434c4d00), + // batch + batch: bytes(0x42434800), } export { HashPrefix } diff --git a/packages/ripple-binary-codec/src/index.ts b/packages/ripple-binary-codec/src/index.ts index d0e44b5bae..4ee74396c0 100644 --- a/packages/ripple-binary-codec/src/index.ts +++ b/packages/ripple-binary-codec/src/index.ts @@ -1,6 +1,6 @@ import { quality, binary, HashPrefix } from './coretypes' import { decodeLedgerData } from './ledger-hashes' -import { ClaimObject } from './binary' +import { ClaimObject, BatchObject } from './binary' import { JsonObject } from './types/serialized-type' import { XrplDefinitionsBase, @@ -15,6 +15,7 @@ const { signingData, signingClaimData, multiSigningData, + signingBatchData, binaryToJSON, serializeObject, } = binary @@ -110,6 +111,13 @@ function encodeForMultisigning( ) } +function encodeForSigningBatch(json: object): string { + if (typeof json !== 'object') { + throw new Error() + } + return bytesToHex(signingBatchData(json as BatchObject)) +} + /** * Encode a quality value * @@ -142,6 +150,7 @@ export { encodeForSigning, encodeForSigningClaim, encodeForMultisigning, + encodeForSigningBatch, encodeQuality, decodeQuality, decodeLedgerData, diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index 0e5a293d21..8b716fd7ae 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -14,6 +14,7 @@ import { encodeForSigning, encodeForMultisigning, encode, + encodeForSigningBatch, } from 'ripple-binary-codec' import { deriveAddress, @@ -463,7 +464,10 @@ export class Wallet { TxIDs: transaction.TxIDs, } // TODO: add multisign support - return sign(encodeForSigning(fieldsToSign), this.privateKey) + return sign( + encodeForSigningBatch(fieldsToSign, this.address), + this.privateKey, + ) } /** From 0d860855df5d418005ecae85af1b4729bdefd730 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 19:56:08 -0400 Subject: [PATCH 16/73] add Batchnet faucet --- .vscode/settings.json | 1 + packages/xrpl/src/Wallet/defaultFaucets.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ef2c734c23..787ced320d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,7 @@ "cSpell.words": [ "altnet", "Autofills", + "Batchnet", "Clawback", "hostid", "keypair", diff --git a/packages/xrpl/src/Wallet/defaultFaucets.ts b/packages/xrpl/src/Wallet/defaultFaucets.ts index bf5c38ae51..188686df7b 100644 --- a/packages/xrpl/src/Wallet/defaultFaucets.ts +++ b/packages/xrpl/src/Wallet/defaultFaucets.ts @@ -14,11 +14,11 @@ export interface FaucetWallet { export enum FaucetNetwork { Testnet = 'faucet.altnet.rippletest.net', Devnet = 'faucet.devnet.rippletest.net', + Batchnet = 'batch.faucet.nerdnest.xyz', } export const FaucetNetworkPaths: Record = { - [FaucetNetwork.Testnet]: '/accounts', - [FaucetNetwork.Devnet]: '/accounts', + // Only need to specify here if not `/accounts` } /** @@ -36,6 +36,10 @@ export function getFaucetHost(client: Client): FaucetNetwork | undefined { return FaucetNetwork.Testnet } + if (connectionUrl.includes('batchnet')) { + return FaucetNetwork.Batchnet + } + if (connectionUrl.includes('sidechain-net2')) { throw new XRPLFaucetError( 'Cannot fund an account on an issuing chain. Accounts must be created via the bridge.', From 438a9d2a3e88af28034776339b7ece62ede9ad18 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 20:29:57 -0400 Subject: [PATCH 17/73] get basic tests working --- packages/ripple-binary-codec/src/binary.ts | 2 +- packages/xrpl/package.json | 2 +- packages/xrpl/src/Wallet/defaultFaucets.ts | 4 +- .../xrpl/src/models/transactions/Batch.ts | 51 +++++-- .../xrpl/src/models/transactions/common.ts | 10 ++ .../xrpl/src/models/transactions/index.ts | 2 +- .../src/models/transactions/transaction.ts | 9 +- packages/xrpl/src/sugar/autofill.ts | 3 +- packages/xrpl/src/utils/hashes/hashLedger.ts | 10 +- packages/xrpl/test/models/Batch.test.ts | 130 +++++++++++------- .../xrpl/test/models/LedgerStateFix.test.ts | 3 +- packages/xrpl/test/utils/hashes.test.ts | 24 ++++ 12 files changed, 180 insertions(+), 70 deletions(-) diff --git a/packages/ripple-binary-codec/src/binary.ts b/packages/ripple-binary-codec/src/binary.ts index 5e1c8c0c2e..19802cab60 100644 --- a/packages/ripple-binary-codec/src/binary.ts +++ b/packages/ripple-binary-codec/src/binary.ts @@ -1,7 +1,7 @@ /* eslint-disable func-style */ import { bytesToHex } from '@xrplf/isomorphic/utils' -import { coreTypes, UInt32 } from './types' +import { coreTypes } from './types' import { BinaryParser } from './serdes/binary-parser' import { AccountID } from './types/account-id' import { HashPrefix } from './hash-prefixes' diff --git a/packages/xrpl/package.json b/packages/xrpl/package.json index fdf05714a4..c44e90675c 100644 --- a/packages/xrpl/package.json +++ b/packages/xrpl/package.json @@ -64,7 +64,7 @@ "test": "jest --config=jest.config.unit.js --verbose false --silent=false", "test:integration": "TS_NODE_PROJECT=tsconfig.build.json jest --config=jest.config.integration.js --verbose false --silent=false --runInBand", "test:browser": "npm run build && npm run build:browserTests && karma start ./karma.config.js", - "test:watch": "jest --watch --verbose false --silent=false --runInBand ./test/**/*.test.ts --testPathIgnorePatterns=./test/integration --testPathIgnorePatterns=./test/fixtures", + "test:watch": "jest --watch --config=jest.config.unit.js --verbose false --silent=false", "format": "prettier --write '{src,test}/**/*.ts'", "lint": "eslint . --ext .ts --max-warnings 0", "perf": "./scripts/perf_test.sh", diff --git a/packages/xrpl/src/Wallet/defaultFaucets.ts b/packages/xrpl/src/Wallet/defaultFaucets.ts index 188686df7b..9c8c079f52 100644 --- a/packages/xrpl/src/Wallet/defaultFaucets.ts +++ b/packages/xrpl/src/Wallet/defaultFaucets.ts @@ -18,7 +18,9 @@ export enum FaucetNetwork { } export const FaucetNetworkPaths: Record = { - // Only need to specify here if not `/accounts` + [FaucetNetwork.Testnet]: '/accounts', + [FaucetNetwork.Devnet]: '/accounts', + [FaucetNetwork.Batchnet]: '/accounts', } /** diff --git a/packages/xrpl/src/models/transactions/Batch.ts b/packages/xrpl/src/models/transactions/Batch.ts index 8492985320..67598bc576 100644 --- a/packages/xrpl/src/models/transactions/Batch.ts +++ b/packages/xrpl/src/models/transactions/Batch.ts @@ -1,7 +1,9 @@ +import { ValidationError } from '../../errors' import { Signer } from '../common' import { BaseTransaction, + isArray, isObject, isString, validateBaseTransaction, @@ -45,7 +47,9 @@ export interface Batch extends BaseTransaction { BatchSigners?: BatchSigner[] - RawTransactions: BatchInnerTransaction[] + RawTransactions: Array<{ + RawTransaction: BatchInnerTransaction + }> /** * Optional because it can be autofilled. @@ -69,37 +73,64 @@ export interface BatchMetadata extends TransactionMetadataBase { * @param tx - A Batch Transaction. * @throws When the Batch is malformed. */ +// eslint-disable-next-line max-lines-per-function -- needed here due to the complexity export function validateBatch(tx: Record): void { validateBaseTransaction(tx) validateRequiredField(tx, 'RawTransactions', isObject) // Full validation of each `RawTransaction` object is done in `validate` to avoid dependency cycles + const rawTransactions = tx.RawTransactions as unknown[] + rawTransactions.forEach((field, index) => { + if (!isObject(field)) { + throw new ValidationError(`Batch: RawTransactions[${index} is not object`) + } + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above + const fieldObject = field as Record + validateRequiredField( + fieldObject, + 'RawTransaction', + isObject, + `RawTransactions[${index}].RawTransaction`, + ) + }) - validateOptionalField(tx, 'BatchSigners', (field) => { + validateOptionalField(tx, 'BatchSigners', isArray) + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above + const batchSigners = tx.BatchSigners as unknown[] + batchSigners.forEach((field, index) => { if (!isObject(field)) { - return false + throw new ValidationError(`Batch: BatchSigners[${index} is not object`) } // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above const fieldObject = field as Record validateRequiredField( fieldObject, + 'BatchSigner', + isObject, + `BatchSigners[${index}].BatchSigner`, + ) + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above + const batchSignerObject = fieldObject.BatchSigner as Record + validateRequiredField( + batchSignerObject, 'Account', isString, - 'BatchSigners.Account', + `BatchSigners[${index}].Account`, ) validateOptionalField( - fieldObject, + batchSignerObject, 'SigningPubKey', isString, - 'BatchSigners.SigningPubKey', + `BatchSigners[${index}].SigningPubKey`, ) validateOptionalField( - fieldObject, + batchSignerObject, 'TxnSignature', isString, - 'BatchSigners.TxnSignature', + `BatchSigners[${index}].TxnSignature`, ) - - return true }) + + validateOptionalField(tx, 'TxIDs', isArray) } diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index fda5ca1fee..feaaf7eb52 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -174,6 +174,16 @@ export function isObject(input: unknown): input is object { return typeof input === 'object' } +/** + * Verify the form and type of an Array at runtime. + * + * @param input - The object to check the form and type of. + * @returns Whether the Array is properly formed. + */ +export function isArray(input: unknown): boolean { + return Array.isArray(input) +} + /* eslint-disable @typescript-eslint/restrict-template-expressions -- tx.TransactionType is checked before any calls */ /** diff --git a/packages/xrpl/src/models/transactions/index.ts b/packages/xrpl/src/models/transactions/index.ts index 8f6bf159c8..946df5b8b5 100644 --- a/packages/xrpl/src/models/transactions/index.ts +++ b/packages/xrpl/src/models/transactions/index.ts @@ -87,4 +87,4 @@ export { XChainModifyBridgeFlagsInterface, } from './XChainModifyBridge' export { Batch } from './batch' -export { LedgerStateFix } from './LedgerStateFix' +export { LedgerStateFix } from './ledgerStateFix' diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index 012f5bae69..913b272b5a 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -27,7 +27,7 @@ import { EnableAmendment } from './enableAmendment' import { EscrowCancel, validateEscrowCancel } from './escrowCancel' import { EscrowCreate, validateEscrowCreate } from './escrowCreate' import { EscrowFinish, validateEscrowFinish } from './escrowFinish' -import { LedgerStateFix, validateLedgerStateFix } from './LedgerStateFix' +import { LedgerStateFix, validateLedgerStateFix } from './ledgerStateFix' import { TransactionMetadata } from './metadata' import { NFTokenAcceptOffer, @@ -277,9 +277,10 @@ export function validate(transaction: Record): void { // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- okay here // @ts-expect-error -- already checked // eslint-disable-next-line @typescript-eslint/no-unsafe-call -- already checked above - tx.RawTransactions.forEach((innerTx: Record) => - validate(innerTx), - ) + tx.RawTransactions.forEach((innerTx: Record) => { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- already checked above + validate(innerTx.RawTransaction as Record) + }) break case 'CheckCancel': diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index b8dce15f28..99e3edcba4 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -421,7 +421,8 @@ export async function autofillBatchTxn( let batchIndex = 0 const txIds: string[] = [] - for await (const txn of tx.RawTransactions) { + for await (const rawTxn of tx.RawTransactions) { + const txn = rawTxn.RawTransaction if (txn.BatchTxn !== undefined) { // eslint-disable-next-line no-continue -- this is fine continue diff --git a/packages/xrpl/src/utils/hashes/hashLedger.ts b/packages/xrpl/src/utils/hashes/hashLedger.ts index ec95e1e7d5..c6dcdf39c2 100644 --- a/packages/xrpl/src/utils/hashes/hashLedger.ts +++ b/packages/xrpl/src/utils/hashes/hashLedger.ts @@ -82,10 +82,12 @@ export function hashSignedTx(tx: Transaction | string): string { } if ( - !('TxnSignature' in txObject) && - !('Signers' in txObject) && - !('SigningPubKey' in txObject) && - !('BatchTxn' in txObject) + txObject.TxnSignature === undefined && + txObject.Signers === undefined && + txObject.SigningPubKey === undefined && + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- exception needed here + // @ts-expect-error -- needed here for Batch transactions + txObject.BatchTxn === undefined ) { throw new ValidationError('The transaction must be signed to hash it.') } diff --git a/packages/xrpl/test/models/Batch.test.ts b/packages/xrpl/test/models/Batch.test.ts index e8f58a18f2..eee0e839bd 100644 --- a/packages/xrpl/test/models/Batch.test.ts +++ b/packages/xrpl/test/models/Batch.test.ts @@ -13,7 +13,60 @@ describe('Batch', function () { beforeEach(function () { tx = { - /* TODO: add sample transaction */ + Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + BatchSigners: [ + { + BatchSigner: { + Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + SigningPubKey: + '02691AC5AE1C4C333AE5DF8A93BDC495F0EEBFC6DB0DA7EB6EF808F3AFC006E3FE', + TxnSignature: + '30450221008E595499C334127A23190F61FB9ADD8B8C501D543E37945B11FABB66B097A6130220138C908E8C4929B47E994A46D611FAC17AB295CFB8D9E0828B32F2947B97394B', + }, + }, + ], + Flags: 1, + RawTransactions: [ + { + RawTransaction: { + Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Amount: '5000000', + BatchTxn: { + BatchIndex: 1, + OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Sequence: 215, + }, + Destination: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Fee: '0', + NetworkID: 21336, + Sequence: 0, + SigningPubKey: '', + TransactionType: 'Payment', + }, + }, + { + RawTransaction: { + Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Amount: '1000000', + BatchTxn: { + BatchIndex: 0, + OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Sequence: 470, + }, + Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Fee: '0', + NetworkID: 21336, + Sequence: 0, + SigningPubKey: '', + TransactionType: 'Payment', + }, + }, + ], + TransactionType: 'Batch', + TxIDs: [ + 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', + '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', + ], } as any }) @@ -22,21 +75,20 @@ describe('Batch', function () { assert.doesNotThrow(() => validate(tx)) }) - // it('throws w/ invalid BatchSigners', function () { - // tx.BatchSigners = - // /* TODO */ + it('throws w/ invalid BatchSigners', function () { + tx.BatchSigners = 0 - // assert.throws( - // () => validateBatch(tx), - // ValidationError, - // 'Batch: invalid field BatchSigners', - // ) - // assert.throws( - // () => validate(tx), - // ValidationError, - // 'Batch: invalid field BatchSigners', - // ) - // }) + assert.throws( + () => validateBatch(tx), + ValidationError, + 'Batch: invalid field BatchSigners', + ) + assert.throws( + () => validate(tx), + ValidationError, + 'Batch: invalid field BatchSigners', + ) + }) it('throws w/ missing RawTransactions', function () { delete tx.RawTransactions @@ -53,46 +105,32 @@ describe('Batch', function () { ) }) - // it('throws w/ invalid RawTransactions', function () { - // tx.RawTransactions = assert.throws( - // () => validateBatch(tx), - // ValidationError, - // 'Batch: invalid field RawTransactions', - // ) - // assert.throws( - // () => validate(tx), - // ValidationError, - // 'Batch: invalid field RawTransactions', - // ) - // }) - - it('throws w/ missing TxIDs', function () { - delete tx.TxIDs - + it('throws w/ invalid RawTransactions', function () { + tx.RawTransactions = 0 assert.throws( () => validateBatch(tx), ValidationError, - 'Batch: missing field TxIDs', + 'Batch: invalid field RawTransactions', ) assert.throws( () => validate(tx), ValidationError, - 'Batch: missing field TxIDs', + 'Batch: invalid field RawTransactions', ) }) - // it('throws w/ invalid TxIDs', function () { - // tx.TxIDs = ['hi'] + it('throws w/ invalid TxIDs', function () { + tx.TxIDs = 0 - // assert.throws( - // () => validateBatch(tx), - // ValidationError, - // 'Batch: invalid field TxIDs', - // ) - // assert.throws( - // () => validate(tx), - // ValidationError, - // 'Batch: invalid field TxIDs', - // ) - // }) + assert.throws( + () => validateBatch(tx), + ValidationError, + 'Batch: invalid field TxIDs', + ) + assert.throws( + () => validate(tx), + ValidationError, + 'Batch: invalid field TxIDs', + ) + }) }) diff --git a/packages/xrpl/test/models/LedgerStateFix.test.ts b/packages/xrpl/test/models/LedgerStateFix.test.ts index e8b1eb2917..c890c9f395 100644 --- a/packages/xrpl/test/models/LedgerStateFix.test.ts +++ b/packages/xrpl/test/models/LedgerStateFix.test.ts @@ -1,7 +1,7 @@ import { assert } from 'chai' import { validate, ValidationError } from '../../src' -import { validateLedgerStateFix } from '../../src/models/transactions/LedgerStateFix' +import { validateLedgerStateFix } from '../../src/models/transactions/ledgerStateFix' /** * LedgerStateFix Transaction Verification Testing. @@ -13,6 +13,7 @@ describe('LedgerStateFix', function () { beforeEach(function () { tx = { + Account: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', TransactionType: 'LedgerStateFix', LedgerFixType: 1, Owner: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', diff --git a/packages/xrpl/test/utils/hashes.test.ts b/packages/xrpl/test/utils/hashes.test.ts index daa42301d4..cd6312f209 100644 --- a/packages/xrpl/test/utils/hashes.test.ts +++ b/packages/xrpl/test/utils/hashes.test.ts @@ -10,6 +10,7 @@ import { Transaction, ValidationError, } from '../../src' +import { BatchInnerTransaction } from '../../src/models/transactions/batch' import { hashStateTree, hashTxTree, @@ -211,4 +212,27 @@ describe('Hashes', function () { 'CA4562711E4679FE9317DD767871E90A404C7A8B84FAFD35EC2CF0231F1F6DAF', ) }) + + it('hashSignedTx - batch transaction', function () { + const transaction: BatchInnerTransaction = { + Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Amount: '1000000', + BatchTxn: { + BatchIndex: 0, + OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Sequence: 470, + }, + Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Fee: '0', + NetworkID: 21336, + Sequence: 0, + SigningPubKey: '', + TransactionType: 'Payment', + } + + assert.equal( + hashSignedTx(transaction), + '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', + ) + }) }) From 591af4722b2b2f1209acabcc4ac4eebb082ff8d0 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Oct 2024 20:49:21 -0400 Subject: [PATCH 18/73] add rbc tests --- packages/ripple-binary-codec/src/binary.ts | 6 +++++ .../test/signing-data-encoding.test.ts | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/packages/ripple-binary-codec/src/binary.ts b/packages/ripple-binary-codec/src/binary.ts index 19802cab60..29dc1589e9 100644 --- a/packages/ripple-binary-codec/src/binary.ts +++ b/packages/ripple-binary-codec/src/binary.ts @@ -193,6 +193,12 @@ interface BatchObject extends JsonObject { * @returns the serialized object with appropriate prefix */ function signingBatchData(batch: BatchObject): Uint8Array { + if (batch.flags == null) { + throw Error("No field `flags'") + } + if (batch.txIDs == null) { + throw Error('No field `txIDs`') + } const prefix = HashPrefix.batch const flags = coreTypes.UInt32.from(batch.flags).toBytes() const txIDsLength = coreTypes.UInt32.from(batch.txIDs.length).toBytes() diff --git a/packages/ripple-binary-codec/test/signing-data-encoding.test.ts b/packages/ripple-binary-codec/test/signing-data-encoding.test.ts index 881f8132af..876afb3deb 100644 --- a/packages/ripple-binary-codec/test/signing-data-encoding.test.ts +++ b/packages/ripple-binary-codec/test/signing-data-encoding.test.ts @@ -1,3 +1,4 @@ +import { encodeForSigningBatch } from '../dist' import { XrplDefinitions } from '../src/enums/xrpl-definitions' const { encodeForSigning, @@ -240,4 +241,27 @@ describe('Signing data', function () { ].join(''), ) }) + + it('can create batch blob', function () { + const flags = 1 + const txIDs = [ + 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', + '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', + ] + const json = { flags, txIDs } + const actual = encodeForSigningBatch(json) + expect(actual).toBe( + [ + // hash prefix + '42434800', + // flags + '00000001', + // txIds length + '00000002', + // txIds + 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', + '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', + ].join(''), + ) + }) }) From 9b8c819e69de1ada3cb7041cbe4f362b6d1dd0a0 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 2 Oct 2024 09:58:00 -0400 Subject: [PATCH 19/73] add autofill tests --- packages/xrpl/src/sugar/autofill.ts | 2 +- packages/xrpl/test/client/autofill.test.ts | 108 +++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 99e3edcba4..8ced19035f 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -444,7 +444,7 @@ export async function autofillBatchTxn( txn.BatchTxn = batchTxn as BatchTxn txIds.push(hashSignedTx(txn)) } - if (tx.TxIDs != null) { + if (tx.TxIDs == null) { // eslint-disable-next-line no-param-reassign -- okay for autofilling tx.TxIDs = txIds } diff --git a/packages/xrpl/test/client/autofill.test.ts b/packages/xrpl/test/client/autofill.test.ts index 8c2d9b5ec8..639ff21d15 100644 --- a/packages/xrpl/test/client/autofill.test.ts +++ b/packages/xrpl/test/client/autofill.test.ts @@ -435,4 +435,112 @@ describe('client.autofill', function () { assert.strictEqual(txResult.Sequence, 23) assert.strictEqual(txResult.LastLedgerSequence, 9038234) }) + + it('should autofill Batch transaction with single account', async function () { + const tx: Transaction = { + TransactionType: 'Batch', + Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + RawTransactions: [ + { + RawTransaction: { + TransactionType: 'DepositPreauth', + Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', + }, + }, + { + RawTransaction: { + TransactionType: 'DepositPreauth', + Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + Authorize: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', + }, + }, + ], + Fee, + Sequence, + LastLedgerSequence, + } + testContext.mockRippled!.addResponse('account_info', { + status: 'success', + type: 'response', + result: { + account_data: { + Sequence: 23, + }, + }, + }) + const txResult = await testContext.client.autofill(tx) + txResult.RawTransactions.forEach((rawTxOuter, index) => { + const rawTx = rawTxOuter.RawTransaction + assert.strictEqual( + rawTx.BatchTxn?.OuterAccount, + 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + ) + assert.strictEqual(rawTx.BatchTxn?.Sequence, 23 + index) + assert.strictEqual(rawTx.BatchTxn?.BatchIndex, index) + }) + assert.strictEqual(txResult.TxIDs?.length, 2) + assert.strictEqual( + txResult.TxIDs?.[0], + 'A63E4FBFADA7A0504F1307F4ADBEDDE70A81C9EFB21D12B6C2824DF21D08862B', + ) + assert.strictEqual( + txResult.TxIDs?.[1], + 'B2A225765BEA821FC074CA0BB803C3BE7B341F801369CF30806DA8CF5D9C0CAB', + ) + }) + + it('should autofill Batch transaction with single account', async function () { + const tx: Transaction = { + TransactionType: 'Batch', + Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + RawTransactions: [ + { + RawTransaction: { + TransactionType: 'DepositPreauth', + Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', + }, + }, + { + RawTransaction: { + TransactionType: 'DepositPreauth', + Account: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', + Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', + }, + }, + ], + Fee, + Sequence, + LastLedgerSequence, + } + testContext.mockRippled!.addResponse('account_info', { + status: 'success', + type: 'response', + result: { + account_data: { + Sequence: 23, + }, + }, + }) + const txResult = await testContext.client.autofill(tx) + txResult.RawTransactions.forEach((rawTxOuter, index) => { + const rawTx = rawTxOuter.RawTransaction + assert.strictEqual( + rawTx.BatchTxn?.OuterAccount, + 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + ) + assert.strictEqual(rawTx.BatchTxn?.Sequence, 23) + assert.strictEqual(rawTx.BatchTxn?.BatchIndex, index) + }) + assert.strictEqual(txResult.TxIDs?.length, 2) + assert.strictEqual( + txResult.TxIDs?.[0], + 'A63E4FBFADA7A0504F1307F4ADBEDDE70A81C9EFB21D12B6C2824DF21D08862B', + ) + assert.strictEqual( + txResult.TxIDs?.[1], + '8C233D6C1394812AFA969E1B91D02F31F35E0D3D813C1DCAFB955E4957FF22D9', + ) + }) }) From 78e3ad9dec85b8f1bc2ba9095a27cd3c251a06d8 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 2 Oct 2024 09:58:38 -0400 Subject: [PATCH 20/73] add signMultiBatch tests --- packages/xrpl/src/Wallet/batch.ts | 81 ++++++++++++++ packages/xrpl/src/Wallet/index.ts | 35 +----- .../xrpl/src/models/transactions/Batch.ts | 9 +- .../xrpl/test/wallet/authorizeChannel.test.ts | 44 ++++---- packages/xrpl/test/wallet/batch.test.ts | 103 ++++++++++++++++++ 5 files changed, 213 insertions(+), 59 deletions(-) create mode 100644 packages/xrpl/src/Wallet/batch.ts create mode 100644 packages/xrpl/test/wallet/batch.test.ts diff --git a/packages/xrpl/src/Wallet/batch.ts b/packages/xrpl/src/Wallet/batch.ts new file mode 100644 index 0000000000..af249e9b8b --- /dev/null +++ b/packages/xrpl/src/Wallet/batch.ts @@ -0,0 +1,81 @@ +import { encodeForSigningBatch } from 'ripple-binary-codec' +import { sign } from 'ripple-keypairs' + +import { ValidationError } from '../errors' +import { Batch, Signer, validate } from '../models' +import { BatchSigner } from '../models/transactions/batch' + +import { Wallet } from '.' + +/** + * Sign a multi-account Batch transaction. + * + * @param wallet - Wallet instance. + * @param transaction - The Batch transaction to sign. + * @param multisign - Specify true/false to use multisign or actual address (classic/x-address) to make multisign tx request. + * @throws ValidationError if the transaction is malformed. + */ +// eslint-disable-next-line max-lines-per-function -- TODO: refactor +export function signMultiBatch( + wallet: Wallet, + transaction: Batch, + multisign?: boolean | string, +): void { + let multisignAddress: boolean | string = false + if (typeof multisign === 'string' && multisign.startsWith('X')) { + multisignAddress = multisign + } else if (multisign) { + multisignAddress = wallet.classicAddress + } + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS + if (transaction.TransactionType !== 'Batch') { + throw new ValidationError('Must be a Batch transaction.') + } + /* + * This will throw a more clear error for JS users if the supplied transaction has incorrect formatting + */ + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type + validate(transaction as unknown as Record) + const fieldsToSign = { + flags: transaction.Flags, + txIDs: transaction.TxIDs, + } + let batchSigner: BatchSigner + if (multisignAddress) { + const signer: Signer = { + Signer: { + Account: multisignAddress, + SigningPubKey: wallet.publicKey, + TxnSignature: sign( + encodeForSigningBatch(fieldsToSign), + wallet.privateKey, + ), + }, + } + batchSigner = { + BatchSigner: { + Account: multisignAddress, + Signers: [signer], + }, + } + } else { + batchSigner = { + BatchSigner: { + Account: wallet.address, + SigningPubKey: wallet.publicKey, + TxnSignature: sign( + encodeForSigningBatch(fieldsToSign), + wallet.privateKey, + ), + }, + } + } + + if (transaction.BatchSigners == null) { + // eslint-disable-next-line no-param-reassign -- okay for signing + transaction.BatchSigners = [batchSigner] + } else { + transaction.BatchSigners.push(batchSigner) + } +} diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index 8b716fd7ae..c5ce5baca5 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -1,4 +1,3 @@ -/* eslint-disable max-lines -- Lots of helper functions needed for signing */ import { HDKey } from '@scure/bip32' import { mnemonicToSeedSync, validateMnemonic } from '@scure/bip39' import { wordlist } from '@scure/bip39/wordlists/english' @@ -14,7 +13,6 @@ import { encodeForSigning, encodeForMultisigning, encode, - encodeForSigningBatch, } from 'ripple-binary-codec' import { deriveAddress, @@ -25,7 +23,7 @@ import { import ECDSA from '../ECDSA' import { ValidationError } from '../errors' -import { Batch, Transaction, validate } from '../models/transactions' +import { Transaction, validate } from '../models/transactions' import { ensureClassicAddress } from '../sugar/utils' import { omitBy } from '../utils/collections' import { hashSignedTx } from '../utils/hashes/hashLedger' @@ -439,37 +437,6 @@ export class Wallet { } } - /** - * Sign a multi-account Batch transaction. - * - * @param this - Wallet instance. - * @param transaction - The Batch transaction to sign - * @returns The signature to include in `BatchSigners`. - * @throws ValidationERror if TxIds isn't included. - */ - public signMultiBatch( - this: Wallet, - transaction: { Flags: number; TxIDs: string[] } | Batch, - ): string { - if (transaction.TxIDs == null) { - throw new ValidationError('Must include TxIDs to sign.') - } - transaction.TxIDs.forEach((txId, index) => { - if (typeof txId !== 'string') { - throw new ValidationError(`TxID #${index} is not a string.`) - } - }) - const fieldsToSign = { - Flags: transaction.Flags, - TxIDs: transaction.TxIDs, - } - // TODO: add multisign support - return sign( - encodeForSigningBatch(fieldsToSign, this.address), - this.privateKey, - ) - } - /** * Verifies a signed transaction offline. * diff --git a/packages/xrpl/src/models/transactions/Batch.ts b/packages/xrpl/src/models/transactions/Batch.ts index 67598bc576..dda8a608dc 100644 --- a/packages/xrpl/src/models/transactions/Batch.ts +++ b/packages/xrpl/src/models/transactions/Batch.ts @@ -77,8 +77,8 @@ export interface BatchMetadata extends TransactionMetadataBase { export function validateBatch(tx: Record): void { validateBaseTransaction(tx) - validateRequiredField(tx, 'RawTransactions', isObject) - // Full validation of each `RawTransaction` object is done in `validate` to avoid dependency cycles + validateRequiredField(tx, 'RawTransactions', isArray) + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above const rawTransactions = tx.RawTransactions as unknown[] rawTransactions.forEach((field, index) => { if (!isObject(field)) { @@ -93,12 +93,13 @@ export function validateBatch(tx: Record): void { `RawTransactions[${index}].RawTransaction`, ) }) + // Full validation of each `RawTransaction` object is done in `validate` to avoid dependency cycles validateOptionalField(tx, 'BatchSigners', isArray) // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const batchSigners = tx.BatchSigners as unknown[] - batchSigners.forEach((field, index) => { + const batchSigners = tx.BatchSigners as unknown[] | undefined + batchSigners?.forEach((field, index) => { if (!isObject(field)) { throw new ValidationError(`Batch: BatchSigners[${index} is not object`) } diff --git a/packages/xrpl/test/wallet/authorizeChannel.test.ts b/packages/xrpl/test/wallet/authorizeChannel.test.ts index f8fd1cb9ca..9681dbe152 100644 --- a/packages/xrpl/test/wallet/authorizeChannel.test.ts +++ b/packages/xrpl/test/wallet/authorizeChannel.test.ts @@ -3,27 +3,29 @@ import { assert } from 'chai' import { ECDSA, Wallet } from '../../src' import { authorizeChannel } from '../../src/Wallet/authorizeChannel' -it('authorizeChannel succeeds with secp256k1 seed', function () { - const secpWallet = Wallet.fromSeed('snGHNrPbHrdUcszeuDEigMdC1Lyyd', { - algorithm: ECDSA.secp256k1, - }) - const channelId = - '5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3' - const amount = '1000000' +describe('authorizeChannel', function () { + it('authorizeChannel succeeds with secp256k1 seed', function () { + const secpWallet = Wallet.fromSeed('snGHNrPbHrdUcszeuDEigMdC1Lyyd', { + algorithm: ECDSA.secp256k1, + }) + const channelId = + '5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3' + const amount = '1000000' - assert.equal( - authorizeChannel(secpWallet, channelId, amount), - '304402204E7052F33DDAFAAA55C9F5B132A5E50EE95B2CF68C0902F61DFE77299BC893740220353640B951DCD24371C16868B3F91B78D38B6F3FD1E826413CDF891FA8250AAC', - ) -}) + assert.equal( + authorizeChannel(secpWallet, channelId, amount), + '304402204E7052F33DDAFAAA55C9F5B132A5E50EE95B2CF68C0902F61DFE77299BC893740220353640B951DCD24371C16868B3F91B78D38B6F3FD1E826413CDF891FA8250AAC', + ) + }) -it('authorizeChannel succeeds with ed25519 seed', function () { - const edWallet = Wallet.fromSeed('sEdSuqBPSQaood2DmNYVkwWTn1oQTj2') - const channelId = - '5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3' - const amount = '1000000' - assert.equal( - authorizeChannel(edWallet, channelId, amount), - '7E1C217A3E4B3C107B7A356E665088B4FBA6464C48C58267BEF64975E3375EA338AE22E6714E3F5E734AE33E6B97AAD59058E1E196C1F92346FC1498D0674404', - ) + it('authorizeChannel succeeds with ed25519 seed', function () { + const edWallet = Wallet.fromSeed('sEdSuqBPSQaood2DmNYVkwWTn1oQTj2') + const channelId = + '5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3' + const amount = '1000000' + assert.equal( + authorizeChannel(edWallet, channelId, amount), + '7E1C217A3E4B3C107B7A356E665088B4FBA6464C48C58267BEF64975E3375EA338AE22E6714E3F5E734AE33E6B97AAD59058E1E196C1F92346FC1498D0674404', + ) + }) }) diff --git a/packages/xrpl/test/wallet/batch.test.ts b/packages/xrpl/test/wallet/batch.test.ts new file mode 100644 index 0000000000..cca5b96d77 --- /dev/null +++ b/packages/xrpl/test/wallet/batch.test.ts @@ -0,0 +1,103 @@ +import { assert } from 'chai' + +import { Batch, ECDSA, Wallet } from '../../src' +import { signMultiBatch } from '../../src/Wallet/batch' + +describe('Wallet batch operations', function () { + describe('signMultiBatch', function () { + let transaction: Batch + + beforeEach(() => { + transaction = { + Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Flags: 1, + RawTransactions: [ + { + RawTransaction: { + Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Amount: '5000000', + BatchTxn: { + BatchIndex: 1, + OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Sequence: 215, + }, + Destination: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Fee: '0', + NetworkID: 21336, + Sequence: 0, + SigningPubKey: '', + TransactionType: 'Payment', + }, + }, + { + RawTransaction: { + Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Amount: '1000000', + BatchTxn: { + BatchIndex: 0, + OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Sequence: 470, + }, + Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Fee: '0', + NetworkID: 21336, + Sequence: 0, + SigningPubKey: '', + TransactionType: 'Payment', + }, + }, + ], + TransactionType: 'Batch', + TxIDs: [ + 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', + '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', + ], + } + }) + it('succeeds with secp256k1 seed', function () { + const secpWallet = Wallet.fromSeed('spkcsko6Ag3RbCSVXV2FJ8Pd4Zac1', { + algorithm: ECDSA.secp256k1, + }) + signMultiBatch(secpWallet, transaction) + const expected = [ + { + BatchSigner: { + Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + SigningPubKey: + '02691AC5AE1C4C333AE5DF8A93BDC495F0EEBFC6DB0DA7EB6EF808F3AFC006E3FE', + TxnSignature: + '30450221008E595499C334127A23190F61FB9ADD8B8C501D543E37945B11FABB66B097A6130220138C908E8C4929B47E994A46D611FAC17AB295CFB8D9E0828B32F2947B97394B', + }, + }, + ] + assert.property(transaction, 'BatchSigners') + assert.strictEqual( + JSON.stringify(transaction.BatchSigners), + JSON.stringify(expected), + ) + }) + + it('succeeds with ed25519 seed', function () { + const edWallet = Wallet.fromSeed('spkcsko6Ag3RbCSVXV2FJ8Pd4Zac1', { + algorithm: ECDSA.ed25519, + }) + signMultiBatch(edWallet, transaction) + const expected = [ + { + BatchSigner: { + Account: 'rJy554HmWFFJQGnRfZuoo8nV97XSMq77h7', + SigningPubKey: + 'ED3CC3D14FD80C213BC92A98AFE13A405A030F845EDCFD5E395286A6E9E62BA638', + TxnSignature: + 'E3337EE8C746523B5F96BEBE1190164B8B384EE2DC99F327D95ABC14E27F3AE16CC00DA7D61FC535DBFF0ADA3AF06394F8A703EE952A141BD871B75166C5CD0A', + }, + }, + ] + assert.property(transaction, 'BatchSigners') + assert.strictEqual( + JSON.stringify(transaction.BatchSigners), + JSON.stringify(expected), + ) + }) + }) +}) From 4e3a5fb34230874b405461c6bb6f50c58e01239f Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 2 Oct 2024 10:35:13 -0400 Subject: [PATCH 21/73] refactor --- packages/xrpl/src/Wallet/batch.ts | 133 ++++++++++++++++++++++++++++- packages/xrpl/src/Wallet/signer.ts | 105 +---------------------- 2 files changed, 131 insertions(+), 107 deletions(-) diff --git a/packages/xrpl/src/Wallet/batch.ts b/packages/xrpl/src/Wallet/batch.ts index af249e9b8b..b53ee7f5f3 100644 --- a/packages/xrpl/src/Wallet/batch.ts +++ b/packages/xrpl/src/Wallet/batch.ts @@ -1,9 +1,12 @@ -import { encodeForSigningBatch } from 'ripple-binary-codec' +import { bytesToHex } from '@xrplf/isomorphic/utils' +import BigNumber from 'bignumber.js' +import { decodeAccountID } from 'ripple-address-codec' +import { decode, encode, encodeForSigningBatch } from 'ripple-binary-codec' import { sign } from 'ripple-keypairs' import { ValidationError } from '../errors' -import { Batch, Signer, validate } from '../models' -import { BatchSigner } from '../models/transactions/batch' +import { Batch, Signer, Transaction, validate } from '../models' +import { BatchSigner, validateBatch } from '../models/transactions/batch' import { Wallet } from '.' @@ -79,3 +82,127 @@ export function signMultiBatch( transaction.BatchSigners.push(batchSigner) } } + +/** + * Takes several transactions with BatchSigners fields (in object or blob form) and creates a + * single transaction with all BatchSigners that then gets signed and returned. + * + * @param transactions The transactions to combine `BatchSigners` values on. + * @returns A single signed Transaction which has all BatchSigners from transactions within it. + * @throws ValidationError if: + * - There were no transactions given to sign + * @category Signing + */ +export function combineBatchSignatures( + transactions: Array, +): string { + if (transactions.length === 0) { + throw new ValidationError('There were 0 transactions to combine') + } + + const decodedTransactions: Transaction[] = transactions.map( + (txOrBlob: string | Transaction) => { + return getDecodedTransaction(txOrBlob) + }, + ) + + decodedTransactions.forEach((tx) => { + if (tx.TransactionType !== 'Batch') { + throw new ValidationError('TransactionType must be `Batch`.') + } + /* + * This will throw a more clear error for JS users if any of the supplied transactions has incorrect formatting + */ + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type + validateBatch(tx as unknown as Record) + if (tx.Signers == null || tx.Signers.length === 0) { + throw new ValidationError( + "For multisigning all transactions must include a Signers field containing an array of signatures. You may have forgotten to pass the 'forMultisign' parameter when signing.", + ) + } + + if (tx.SigningPubKey !== '') { + throw new ValidationError( + 'SigningPubKey must be an empty string for all transactions when multisigning.', + ) + } + }) + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above + const batchTransactions = decodedTransactions as Batch[] + + validateBatchTransactionEquivalence(batchTransactions) + + return encode(getTransactionWithAllBatchSigners(batchTransactions)) +} + +/** + * The transactions should all be equal except for the 'Signers' field. + * + * @param transactions - An array of Transactions which are expected to be equal other than 'Signers'. + * @throws ValidationError if the transactions are not equal in any field other than 'Signers'. + */ +function validateBatchTransactionEquivalence(transactions: Batch[]): void { + const exampleTransaction = JSON.stringify({ + Flags: transactions[0].Flags, + TxIDs: transactions[0].TxIDs, + }) + if ( + transactions + .slice(1) + .some( + (tx) => + JSON.stringify({ Flags: tx.Flags, TxIDs: tx.TxIDs }) !== + exampleTransaction, + ) + ) { + throw new ValidationError( + 'Flags and TxIDs is not the same for all provided transactions', + ) + } +} + +function getTransactionWithAllBatchSigners(transactions: Batch[]): Transaction { + // Signers must be sorted in the combined transaction - See compareSigners' documentation for more details + const sortedSigners: BatchSigner[] = transactions + .flatMap((tx) => tx.BatchSigners ?? []) + .sort(compareBatchSigners) + + return { ...transactions[0], BatchSigners: sortedSigners } +} + +/** + * If presented in binary form, the BatchSigners array must be sorted based on + * the numeric value of the signer addresses, with the lowest value first. + * (If submitted as JSON, the submit_multisigned method handles this automatically.) + * https://xrpl.org/multi-signing.html. + * + * @param left - A BatchSigner to compare with. + * @param right - A second BatchSigner to compare with. + * @returns 1 if left \> right, 0 if left = right, -1 if left \< right, and null if left or right are NaN. + */ +function compareBatchSigners(left: BatchSigner, right: BatchSigner): number { + return addressToBigNumber(left.BatchSigner.Account).comparedTo( + addressToBigNumber(right.BatchSigner.Account), + ) +} + +// copied from signer.ts +// TODO: refactor +const NUM_BITS_IN_HEX = 16 + +function addressToBigNumber(address: string): BigNumber { + const hex = bytesToHex(decodeAccountID(address)) + return new BigNumber(hex, NUM_BITS_IN_HEX) +} + +function getDecodedTransaction(txOrBlob: Transaction | string): Transaction { + if (typeof txOrBlob === 'object') { + // We need this to handle X-addresses in multisigning + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We are casting here to get strong typing + return decode(encode(txOrBlob)) as unknown as Transaction + } + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We are casting here to get strong typing + return decode(txOrBlob) as unknown as Transaction +} diff --git a/packages/xrpl/src/Wallet/signer.ts b/packages/xrpl/src/Wallet/signer.ts index 04da21c0ac..126e629cd7 100644 --- a/packages/xrpl/src/Wallet/signer.ts +++ b/packages/xrpl/src/Wallet/signer.ts @@ -7,7 +7,6 @@ import { verify } from 'ripple-keypairs' import { ValidationError } from '../errors' import { Signer } from '../models/common' import { Transaction, validate } from '../models/transactions' -import { Batch, BatchSigner, validateBatch } from '../models/transactions/batch' /** * Takes several transactions with Signer fields (in object or blob form) and creates a @@ -56,57 +55,6 @@ function multisign(transactions: Array): string { return encode(getTransactionWithAllSigners(decodedTransactions)) } -/** - * Takes several transactions with BatchSigners fields (in object or blob form) and creates a - * single transaction with all BatchSigners that then gets signed and returned. - * - * @param transactions The transactions to combine `BatchSigners` values on. - * @returns A single signed Transaction which has all BatchSigners from transactions within it. - * @throws ValidationError if: - * - There were no transactions given to sign - * @category Signing - */ -function combineBatchSignatures(transactions: Array): string { - if (transactions.length === 0) { - throw new ValidationError('There were 0 transactions to combine') - } - - const decodedTransactions: Transaction[] = transactions.map( - (txOrBlob: string | Transaction) => { - return getDecodedTransaction(txOrBlob) - }, - ) - - decodedTransactions.forEach((tx) => { - if (tx.TransactionType !== 'Batch') { - throw new ValidationError('TransactionType must be `Batch`.') - } - /* - * This will throw a more clear error for JS users if any of the supplied transactions has incorrect formatting - */ - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type - validateBatch(tx as unknown as Record) - if (tx.Signers == null || tx.Signers.length === 0) { - throw new ValidationError( - "For multisigning all transactions must include a Signers field containing an array of signatures. You may have forgotten to pass the 'forMultisign' parameter when signing.", - ) - } - - if (tx.SigningPubKey !== '') { - throw new ValidationError( - 'SigningPubKey must be an empty string for all transactions when multisigning.', - ) - } - }) - - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const batchTransactions = decodedTransactions as Batch[] - - validateBatchTransactionEquivalence(batchTransactions) - - return encode(getTransactionWithAllBatchSigners(batchTransactions)) -} - /** * Verifies that the given transaction has a valid signature based on public-key encryption. * @@ -167,32 +115,6 @@ function validateTransactionEquivalence(transactions: Transaction[]): void { } } -/** - * The transactions should all be equal except for the 'Signers' field. - * - * @param transactions - An array of Transactions which are expected to be equal other than 'Signers'. - * @throws ValidationError if the transactions are not equal in any field other than 'Signers'. - */ -function validateBatchTransactionEquivalence(transactions: Batch[]): void { - const exampleTransaction = JSON.stringify({ - Flags: transactions[0].Flags, - TxIDs: transactions[0].TxIDs, - }) - if ( - transactions - .slice(1) - .some( - (tx) => - JSON.stringify({ Flags: tx.Flags, TxIDs: tx.TxIDs }) !== - exampleTransaction, - ) - ) { - throw new ValidationError( - 'Flags and TxIDs is not the same for all provided transactions', - ) - } -} - function getTransactionWithAllSigners( transactions: Transaction[], ): Transaction { @@ -204,15 +126,6 @@ function getTransactionWithAllSigners( return { ...transactions[0], Signers: sortedSigners } } -function getTransactionWithAllBatchSigners(transactions: Batch[]): Transaction { - // Signers must be sorted in the combined transaction - See compareSigners' documentation for more details - const sortedSigners: BatchSigner[] = transactions - .flatMap((tx) => tx.BatchSigners ?? []) - .sort(compareBatchSigners) - - return { ...transactions[0], BatchSigners: sortedSigners } -} - /** * If presented in binary form, the Signers array must be sorted based on * the numeric value of the signer addresses, with the lowest value first. @@ -229,22 +142,6 @@ function compareSigners(left: Signer, right: Signer): number { ) } -/** - * If presented in binary form, the BatchSigners array must be sorted based on - * the numeric value of the signer addresses, with the lowest value first. - * (If submitted as JSON, the submit_multisigned method handles this automatically.) - * https://xrpl.org/multi-signing.html. - * - * @param left - A BatchSigner to compare with. - * @param right - A second BatchSigner to compare with. - * @returns 1 if left \> right, 0 if left = right, -1 if left \< right, and null if left or right are NaN. - */ -function compareBatchSigners(left: BatchSigner, right: BatchSigner): number { - return addressToBigNumber(left.BatchSigner.Account).comparedTo( - addressToBigNumber(right.BatchSigner.Account), - ) -} - const NUM_BITS_IN_HEX = 16 function addressToBigNumber(address: string): BigNumber { @@ -263,4 +160,4 @@ function getDecodedTransaction(txOrBlob: Transaction | string): Transaction { return decode(txOrBlob) as unknown as Transaction } -export { combineBatchSignatures, verifySignature, multisign } +export { verifySignature, multisign } From 7fb99279b73da1e2692dc56bf6472791b7c83cc1 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 2 Oct 2024 10:53:53 -0400 Subject: [PATCH 22/73] add basic tests for combineBatchSigners --- .../src/Wallet/{batch.ts => batchSigner.ts} | 13 +-- .../{batch.test.ts => batchSigner.test.ts} | 100 ++++++++++++++++-- 2 files changed, 99 insertions(+), 14 deletions(-) rename packages/xrpl/src/Wallet/{batch.ts => batchSigner.ts} (96%) rename packages/xrpl/test/wallet/{batch.test.ts => batchSigner.test.ts} (51%) diff --git a/packages/xrpl/src/Wallet/batch.ts b/packages/xrpl/src/Wallet/batchSigner.ts similarity index 96% rename from packages/xrpl/src/Wallet/batch.ts rename to packages/xrpl/src/Wallet/batchSigner.ts index b53ee7f5f3..232d121c36 100644 --- a/packages/xrpl/src/Wallet/batch.ts +++ b/packages/xrpl/src/Wallet/batchSigner.ts @@ -93,7 +93,7 @@ export function signMultiBatch( * - There were no transactions given to sign * @category Signing */ -export function combineBatchSignatures( +export function combineBatchSigners( transactions: Array, ): string { if (transactions.length === 0) { @@ -115,16 +115,17 @@ export function combineBatchSignatures( */ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type validateBatch(tx as unknown as Record) - if (tx.Signers == null || tx.Signers.length === 0) { + if (tx.BatchSigners == null || tx.BatchSigners.length === 0) { throw new ValidationError( "For multisigning all transactions must include a Signers field containing an array of signatures. You may have forgotten to pass the 'forMultisign' parameter when signing.", ) } - if (tx.SigningPubKey !== '') { - throw new ValidationError( - 'SigningPubKey must be an empty string for all transactions when multisigning.', - ) + if ( + tx.SigningPubKey !== '' && + (tx.TxnSignature != null || tx.Signers != null) + ) { + throw new ValidationError('Transaction must be unsigned.') } }) diff --git a/packages/xrpl/test/wallet/batch.test.ts b/packages/xrpl/test/wallet/batchSigner.test.ts similarity index 51% rename from packages/xrpl/test/wallet/batch.test.ts rename to packages/xrpl/test/wallet/batchSigner.test.ts index cca5b96d77..f08c7f9977 100644 --- a/packages/xrpl/test/wallet/batch.test.ts +++ b/packages/xrpl/test/wallet/batchSigner.test.ts @@ -1,7 +1,20 @@ import { assert } from 'chai' -import { Batch, ECDSA, Wallet } from '../../src' -import { signMultiBatch } from '../../src/Wallet/batch' +import { Batch, decode, ECDSA, encode, Wallet } from '../../src' +import { + combineBatchSigners, + signMultiBatch, +} from '../../src/Wallet/batchSigner' + +const secpWallet = Wallet.fromSeed('spkcsko6Ag3RbCSVXV2FJ8Pd4Zac1', { + algorithm: ECDSA.secp256k1, +}) +const edWallet = Wallet.fromSeed('spkcsko6Ag3RbCSVXV2FJ8Pd4Zac1', { + algorithm: ECDSA.ed25519, +}) +// const submitWallet = Wallet.fromSeed('sEd7HmQFsoyj5TAm6d98gytM9LJA1MF', { +// algorithm: ECDSA.ed25519, +// }) describe('Wallet batch operations', function () { describe('signMultiBatch', function () { @@ -55,9 +68,6 @@ describe('Wallet batch operations', function () { } }) it('succeeds with secp256k1 seed', function () { - const secpWallet = Wallet.fromSeed('spkcsko6Ag3RbCSVXV2FJ8Pd4Zac1', { - algorithm: ECDSA.secp256k1, - }) signMultiBatch(secpWallet, transaction) const expected = [ { @@ -78,9 +88,6 @@ describe('Wallet batch operations', function () { }) it('succeeds with ed25519 seed', function () { - const edWallet = Wallet.fromSeed('spkcsko6Ag3RbCSVXV2FJ8Pd4Zac1', { - algorithm: ECDSA.ed25519, - }) signMultiBatch(edWallet, transaction) const expected = [ { @@ -100,4 +107,81 @@ describe('Wallet batch operations', function () { ) }) }) + + describe('combineBatchSigners', function () { + let tx1: Batch + let tx2: Batch + const originalTx: Batch = { + Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Flags: 1, + LastLedgerSequence: 14973, + NetworkID: 21336, + RawTransactions: [ + { + RawTransaction: { + Account: 'rJy554HmWFFJQGnRfZuoo8nV97XSMq77h7', + Amount: '5000000', + BatchTxn: { + BatchIndex: 1, + OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Sequence: 215, + }, + Destination: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Fee: '0', + NetworkID: 21336, + Sequence: 0, + SigningPubKey: '', + TransactionType: 'Payment', + }, + }, + { + RawTransaction: { + Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Amount: '1000000', + BatchTxn: { + BatchIndex: 0, + OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Sequence: 470, + }, + Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Fee: '0', + NetworkID: 21336, + Sequence: 0, + SigningPubKey: '', + TransactionType: 'Payment', + }, + }, + ], + Sequence: 215, + TransactionType: 'Batch', + TxIDs: [ + 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', + '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', + ], + } + let expectedValid + + beforeEach(() => { + tx1 = { ...originalTx } + tx2 = { ...originalTx } + signMultiBatch(edWallet, tx1) + signMultiBatch(secpWallet, tx2) + expectedValid = (tx1.BatchSigners ?? []).concat(tx2.BatchSigners ?? []) + }) + + it('combines valid transactions', function () { + const result = combineBatchSigners([tx1, tx2]) + assert.deepEqual(decode(result).BatchSigners, expectedValid) + }) + + it('combines valid serialized transactions', function () { + const result = combineBatchSigners([encode(tx1), encode(tx2)]) + assert.deepEqual(decode(result).BatchSigners, expectedValid) + }) + + it('sorts the signers', function () { + const result = combineBatchSigners([tx2, tx1]) + assert.deepEqual(decode(result).BatchSigners, expectedValid) + }) + }) }) From 447c747f0fae6200c0d36b9b611585acd48a85c1 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 2 Oct 2024 11:18:48 -0400 Subject: [PATCH 23/73] handle more edge cases --- packages/xrpl/src/Wallet/batchSigner.ts | 17 +++-- packages/xrpl/test/wallet/batchSigner.test.ts | 71 +++++++++++++++++-- 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/packages/xrpl/src/Wallet/batchSigner.ts b/packages/xrpl/src/Wallet/batchSigner.ts index 232d121c36..2f1844bf62 100644 --- a/packages/xrpl/src/Wallet/batchSigner.ts +++ b/packages/xrpl/src/Wallet/batchSigner.ts @@ -30,6 +30,14 @@ export function signMultiBatch( } else if (multisign) { multisignAddress = wallet.classicAddress } + const involvedAccounts = transaction.RawTransactions.map( + (raw) => raw.RawTransaction.Account, + ) + if (!involvedAccounts.includes(multisignAddress || wallet.address)) { + throw new ValidationError( + 'Must be signing for an address included in the Batch.', + ) + } // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS if (transaction.TransactionType !== 'Batch') { @@ -75,12 +83,8 @@ export function signMultiBatch( } } - if (transaction.BatchSigners == null) { - // eslint-disable-next-line no-param-reassign -- okay for signing - transaction.BatchSigners = [batchSigner] - } else { - transaction.BatchSigners.push(batchSigner) - } + // eslint-disable-next-line no-param-reassign -- okay for signing + transaction.BatchSigners = [batchSigner] } /** @@ -167,6 +171,7 @@ function getTransactionWithAllBatchSigners(transactions: Batch[]): Transaction { // Signers must be sorted in the combined transaction - See compareSigners' documentation for more details const sortedSigners: BatchSigner[] = transactions .flatMap((tx) => tx.BatchSigners ?? []) + .filter((signer) => signer.BatchSigner.Account !== transactions[0].Account) .sort(compareBatchSigners) return { ...transactions[0], BatchSigners: sortedSigners } diff --git a/packages/xrpl/test/wallet/batchSigner.test.ts b/packages/xrpl/test/wallet/batchSigner.test.ts index f08c7f9977..782c72f24b 100644 --- a/packages/xrpl/test/wallet/batchSigner.test.ts +++ b/packages/xrpl/test/wallet/batchSigner.test.ts @@ -1,6 +1,15 @@ import { assert } from 'chai' -import { Batch, decode, ECDSA, encode, Wallet } from '../../src' +import { + Batch, + decode, + ECDSA, + encode, + ValidationError, + Wallet, +} from '../../src' +import { BatchInnerTransaction } from '../../src/models/transactions/batch' +import { hashSignedTx } from '../../src/utils/hashes' import { combineBatchSigners, signMultiBatch, @@ -12,9 +21,14 @@ const secpWallet = Wallet.fromSeed('spkcsko6Ag3RbCSVXV2FJ8Pd4Zac1', { const edWallet = Wallet.fromSeed('spkcsko6Ag3RbCSVXV2FJ8Pd4Zac1', { algorithm: ECDSA.ed25519, }) -// const submitWallet = Wallet.fromSeed('sEd7HmQFsoyj5TAm6d98gytM9LJA1MF', { -// algorithm: ECDSA.ed25519, -// }) +const submitWallet = Wallet.fromSeed('sEd7HmQFsoyj5TAm6d98gytM9LJA1MF', { + algorithm: ECDSA.ed25519, +}) +const otherWallet = Wallet.generate() + +interface RawTransaction { + RawTransaction: BatchInnerTransaction +} describe('Wallet batch operations', function () { describe('signMultiBatch', function () { @@ -27,7 +41,7 @@ describe('Wallet batch operations', function () { RawTransactions: [ { RawTransaction: { - Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Account: 'rJy554HmWFFJQGnRfZuoo8nV97XSMq77h7', Amount: '5000000', BatchTxn: { BatchIndex: 1, @@ -106,6 +120,14 @@ describe('Wallet batch operations', function () { JSON.stringify(expected), ) }) + + it('fails with not-included account', function () { + assert.throws( + () => signMultiBatch(otherWallet, transaction), + ValidationError, + 'Must be signing for an address included in the Batch.', + ) + }) }) describe('combineBatchSigners', function () { @@ -183,5 +205,44 @@ describe('Wallet batch operations', function () { const result = combineBatchSigners([tx2, tx1]) assert.deepEqual(decode(result).BatchSigners, expectedValid) }) + + it('removes signer for Batch submitter', function () { + // add a third inner transaction from the transaction submitter + const rawTx3: RawTransaction = { + RawTransaction: { + Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Amount: '1000000', + BatchTxn: { + BatchIndex: 0, + OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Sequence: 470, + }, + Destination: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Fee: '0', + NetworkID: 21336, + Sequence: 0, + SigningPubKey: '', + TransactionType: 'Payment', + }, + } + const rawTxs = originalTx.RawTransactions.concat(rawTx3) + const txIds = originalTx.TxIDs?.concat([ + hashSignedTx(rawTx3.RawTransaction), + ]) + + // set up all the transactions again (repeat what's done in `beforeEach`) + const newTx = { ...originalTx, RawTransactions: rawTxs, TxIDs: txIds } + tx1 = { ...newTx } + tx2 = { ...newTx } + const tx3 = { ...newTx } + signMultiBatch(edWallet, tx1) + signMultiBatch(secpWallet, tx2) + signMultiBatch(submitWallet, tx3) + + // run test + const result = combineBatchSigners([tx1, tx2, tx3]) + const expected = (tx1.BatchSigners ?? []).concat(tx2.BatchSigners ?? []) + assert.deepEqual(decode(result).BatchSigners, expected) + }) }) }) From 4d8493073e484a9ecdf3343cdb844695f6572e95 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 2 Oct 2024 23:27:47 -0400 Subject: [PATCH 24/73] better error validation --- packages/xrpl/src/Wallet/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index c5ce5baca5..93998633c9 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -407,6 +407,10 @@ export class Wallet { */ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type validate(tx as unknown as Record) + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- needed here for JS validation + if ((tx as unknown as Record).BatchTxn != null) { + throw new ValidationError('Cannot sign a Batch inner transaction.') + } const txToSignAndEncode = { ...tx } From f120ea668af8acad51b304b4604a1f2d36f4cc0a Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 3 Oct 2024 11:10:59 -0400 Subject: [PATCH 25/73] rename --- packages/xrpl/src/models/transactions/{Batch.ts => batch.ts} | 0 .../models/transactions/{LedgerStateFix.ts => ledgerStateFix.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/xrpl/src/models/transactions/{Batch.ts => batch.ts} (100%) rename packages/xrpl/src/models/transactions/{LedgerStateFix.ts => ledgerStateFix.ts} (100%) diff --git a/packages/xrpl/src/models/transactions/Batch.ts b/packages/xrpl/src/models/transactions/batch.ts similarity index 100% rename from packages/xrpl/src/models/transactions/Batch.ts rename to packages/xrpl/src/models/transactions/batch.ts diff --git a/packages/xrpl/src/models/transactions/LedgerStateFix.ts b/packages/xrpl/src/models/transactions/ledgerStateFix.ts similarity index 100% rename from packages/xrpl/src/models/transactions/LedgerStateFix.ts rename to packages/xrpl/src/models/transactions/ledgerStateFix.ts From 009e98f1723a99b2a60ad0cb0fa20b88c76694e5 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Mon, 7 Oct 2024 10:43:17 -0700 Subject: [PATCH 26/73] update history --- packages/ripple-binary-codec/HISTORY.md | 2 ++ packages/xrpl/HISTORY.md | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/ripple-binary-codec/HISTORY.md b/packages/ripple-binary-codec/HISTORY.md index a0710d4eba..47c6f70e3a 100644 --- a/packages/ripple-binary-codec/HISTORY.md +++ b/packages/ripple-binary-codec/HISTORY.md @@ -2,6 +2,8 @@ ## Unreleased +* Support for the `Batch` amendment (XLS-56). + ## 2.1.0 (2024-06-03) ### Added diff --git a/packages/xrpl/HISTORY.md b/packages/xrpl/HISTORY.md index e6deb8457b..d5de98eb9a 100644 --- a/packages/xrpl/HISTORY.md +++ b/packages/xrpl/HISTORY.md @@ -6,6 +6,7 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr ### Added * parseTransactionFlags as a utility function in the xrpl package to streamline transactions flags-to-map conversion +* Add support for `Batch` amendment ## 4.0.0 (2024-07-15) From 211d46a162f5b780f1365525cc5b66241efed110 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 9 Oct 2024 10:59:00 -0700 Subject: [PATCH 27/73] fix import --- packages/ripple-binary-codec/test/signing-data-encoding.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ripple-binary-codec/test/signing-data-encoding.test.ts b/packages/ripple-binary-codec/test/signing-data-encoding.test.ts index 876afb3deb..ee37161aea 100644 --- a/packages/ripple-binary-codec/test/signing-data-encoding.test.ts +++ b/packages/ripple-binary-codec/test/signing-data-encoding.test.ts @@ -1,9 +1,9 @@ -import { encodeForSigningBatch } from '../dist' import { XrplDefinitions } from '../src/enums/xrpl-definitions' const { encodeForSigning, encodeForSigningClaim, encodeForMultisigning, + encodeForSigningBatch, } = require('../src') const normalDefinitions = require('../src/enums/definitions.json') From ff9929c3078ee9259297bb1452a1cab6a2bc6f16 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 10 Oct 2024 15:44:29 -0700 Subject: [PATCH 28/73] add more validation --- packages/xrpl/src/Wallet/batchSigner.ts | 8 ++++---- packages/xrpl/src/models/transactions/batch.ts | 12 ++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/xrpl/src/Wallet/batchSigner.ts b/packages/xrpl/src/Wallet/batchSigner.ts index 2f1844bf62..ce709f1b54 100644 --- a/packages/xrpl/src/Wallet/batchSigner.ts +++ b/packages/xrpl/src/Wallet/batchSigner.ts @@ -101,7 +101,7 @@ export function combineBatchSigners( transactions: Array, ): string { if (transactions.length === 0) { - throw new ValidationError('There were 0 transactions to combine') + throw new ValidationError('There were 0 transactions to combine.') } const decodedTransactions: Transaction[] = transactions.map( @@ -121,7 +121,7 @@ export function combineBatchSigners( validateBatch(tx as unknown as Record) if (tx.BatchSigners == null || tx.BatchSigners.length === 0) { throw new ValidationError( - "For multisigning all transactions must include a Signers field containing an array of signatures. You may have forgotten to pass the 'forMultisign' parameter when signing.", + 'For combining Batch transaction signatures, all transactions must include a BatchSigners field containing an array of signatures.', ) } @@ -162,12 +162,12 @@ function validateBatchTransactionEquivalence(transactions: Batch[]): void { ) ) { throw new ValidationError( - 'Flags and TxIDs is not the same for all provided transactions', + 'Flags and TxIDs is not the same for all provided transactions.', ) } } -function getTransactionWithAllBatchSigners(transactions: Batch[]): Transaction { +function getTransactionWithAllBatchSigners(transactions: Batch[]): Batch { // Signers must be sorted in the combined transaction - See compareSigners' documentation for more details const sortedSigners: BatchSigner[] = transactions .flatMap((tx) => tx.BatchSigners ?? []) diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index dda8a608dc..9e7b40a818 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -92,6 +92,18 @@ export function validateBatch(tx: Record): void { isObject, `RawTransactions[${index}].RawTransaction`, ) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- needed here + // @ts-expect-error -- checked above + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above + const rawTx = field.RawTransaction as Record + if (!isObject(rawTx)) { + throw new ValidationError(`Batch: RawTransactions[${index} is not object`) + } + if (rawTx.TransactionType === 'Batch') { + throw new ValidationError( + `Batch: RawTransactions[${index} is a Batch transaction. Cannot nest Batch transactions.`, + ) + } }) // Full validation of each `RawTransaction` object is done in `validate` to avoid dependency cycles From 7212c5e1330883a0b16359d3bbba8d4bfb2d71e5 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 7 Nov 2024 13:01:30 -0500 Subject: [PATCH 29/73] remove BatchTxn, fix autofill --- packages/xrpl/.eslintrc.js | 2 +- .../src/models/transactions/AMMDeposit.ts | 4 +- .../src/models/transactions/AMMWithdraw.ts | 4 +- .../models/transactions/NFTokenCreateOffer.ts | 4 +- .../src/models/transactions/NFTokenMint.ts | 4 +- .../models/transactions/XChainModifyBridge.ts | 4 +- .../src/models/transactions/accountSet.ts | 3 +- .../xrpl/src/models/transactions/batch.ts | 16 +++--- .../xrpl/src/models/transactions/common.ts | 11 ++-- .../src/models/transactions/offerCreate.ts | 4 +- .../xrpl/src/models/transactions/payment.ts | 4 +- .../transactions/paymentChannelClaim.ts | 9 +++- .../xrpl/src/models/transactions/trustSet.ts | 4 +- packages/xrpl/src/models/utils/flags.ts | 11 ++-- packages/xrpl/src/sugar/autofill.ts | 51 +++++++++++-------- 15 files changed, 78 insertions(+), 57 deletions(-) diff --git a/packages/xrpl/.eslintrc.js b/packages/xrpl/.eslintrc.js index 2321616dfa..9e4eabd1db 100644 --- a/packages/xrpl/.eslintrc.js +++ b/packages/xrpl/.eslintrc.js @@ -66,6 +66,7 @@ module.exports = { 'tsdoc/syntax': 'off', 'jsdoc/require-description-complete-sentence': 'off', 'import/prefer-default-export': 'off', + 'max-depth': ['warn', 3], }, overrides: [ { @@ -155,7 +156,6 @@ module.exports = { 'max-lines-per-function': ['off'], 'max-statements': ['off'], complexity: ['off'], - 'max-depth': ['warn', 3], }, }, ], diff --git a/packages/xrpl/src/models/transactions/AMMDeposit.ts b/packages/xrpl/src/models/transactions/AMMDeposit.ts index 2dd8d27e39..884d06ac4c 100644 --- a/packages/xrpl/src/models/transactions/AMMDeposit.ts +++ b/packages/xrpl/src/models/transactions/AMMDeposit.ts @@ -3,7 +3,7 @@ import { Amount, Currency, IssuedCurrencyAmount } from '../common' import { BaseTransaction, - GlobalFlags, + GlobalFlagsInterface, isAmount, isCurrency, isIssuedCurrency, @@ -24,7 +24,7 @@ export enum AMMDepositFlags { tfTwoAssetIfEmpty = 0x00800000, } -export interface AMMDepositFlagsInterface extends GlobalFlags { +export interface AMMDepositFlagsInterface extends GlobalFlagsInterface { tfLPToken?: boolean tfSingleAsset?: boolean tfTwoAsset?: boolean diff --git a/packages/xrpl/src/models/transactions/AMMWithdraw.ts b/packages/xrpl/src/models/transactions/AMMWithdraw.ts index fcce5912b3..bc668afff1 100644 --- a/packages/xrpl/src/models/transactions/AMMWithdraw.ts +++ b/packages/xrpl/src/models/transactions/AMMWithdraw.ts @@ -3,7 +3,7 @@ import { Amount, Currency, IssuedCurrencyAmount } from '../common' import { BaseTransaction, - GlobalFlags, + GlobalFlagsInterface, isAmount, isCurrency, isIssuedCurrency, @@ -25,7 +25,7 @@ export enum AMMWithdrawFlags { tfLimitLPToken = 0x00400000, } -export interface AMMWithdrawFlagsInterface extends GlobalFlags { +export interface AMMWithdrawFlagsInterface extends GlobalFlagsInterface { tfLPToken?: boolean tfWithdrawAll?: boolean tfOneAssetWithdrawAll?: boolean diff --git a/packages/xrpl/src/models/transactions/NFTokenCreateOffer.ts b/packages/xrpl/src/models/transactions/NFTokenCreateOffer.ts index 9575d1b6be..ae42ca4874 100644 --- a/packages/xrpl/src/models/transactions/NFTokenCreateOffer.ts +++ b/packages/xrpl/src/models/transactions/NFTokenCreateOffer.ts @@ -4,7 +4,7 @@ import { isFlagEnabled } from '../utils' import { BaseTransaction, - GlobalFlags, + GlobalFlagsInterface, validateBaseTransaction, isAmount, parseAmountValue, @@ -33,7 +33,7 @@ export enum NFTokenCreateOfferFlags { * * @category Transaction Flags */ -export interface NFTokenCreateOfferFlagsInterface extends GlobalFlags { +export interface NFTokenCreateOfferFlagsInterface extends GlobalFlagsInterface { tfSellNFToken?: boolean } diff --git a/packages/xrpl/src/models/transactions/NFTokenMint.ts b/packages/xrpl/src/models/transactions/NFTokenMint.ts index 2630a6b9c6..6fe03e0241 100644 --- a/packages/xrpl/src/models/transactions/NFTokenMint.ts +++ b/packages/xrpl/src/models/transactions/NFTokenMint.ts @@ -4,7 +4,7 @@ import { isHex } from '../utils' import { Account, BaseTransaction, - GlobalFlags, + GlobalFlagsInterface, isAccount, validateBaseTransaction, validateOptionalField, @@ -46,7 +46,7 @@ export enum NFTokenMintFlags { * * @category Transaction Flags */ -export interface NFTokenMintFlagsInterface extends GlobalFlags { +export interface NFTokenMintFlagsInterface extends GlobalFlagsInterface { tfBurnable?: boolean tfOnlyXRP?: boolean tfTrustLine?: boolean diff --git a/packages/xrpl/src/models/transactions/XChainModifyBridge.ts b/packages/xrpl/src/models/transactions/XChainModifyBridge.ts index 841960b8f0..4825106b79 100644 --- a/packages/xrpl/src/models/transactions/XChainModifyBridge.ts +++ b/packages/xrpl/src/models/transactions/XChainModifyBridge.ts @@ -2,7 +2,7 @@ import { Amount, XChainBridge } from '../common' import { BaseTransaction, - GlobalFlags, + GlobalFlagsInterface, isAmount, isXChainBridge, validateBaseTransaction, @@ -26,7 +26,7 @@ export enum XChainModifyBridgeFlags { * * @category Transaction Flags */ -export interface XChainModifyBridgeFlagsInterface extends GlobalFlags { +export interface XChainModifyBridgeFlagsInterface extends GlobalFlagsInterface { /** Clears the MinAccountCreateAmount of the bridge. */ tfClearAccountCreateAmount?: boolean } diff --git a/packages/xrpl/src/models/transactions/accountSet.ts b/packages/xrpl/src/models/transactions/accountSet.ts index 1d4c9078a5..8a74c51e6e 100644 --- a/packages/xrpl/src/models/transactions/accountSet.ts +++ b/packages/xrpl/src/models/transactions/accountSet.ts @@ -3,6 +3,7 @@ import { ValidationError } from '../../errors' import { Account, BaseTransaction, + GlobalFlagsInterface, isAccount, validateBaseTransaction, validateOptionalField, @@ -112,7 +113,7 @@ export enum AccountSetTfFlags { * // } * ``` */ -export interface AccountSetFlagsInterface { +export interface AccountSetFlagsInterface extends GlobalFlagsInterface { tfRequireDestTag?: boolean tfOptionalDestTag?: boolean tfRequireAuth?: boolean diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index 9e7b40a818..6c848a35e6 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -13,18 +13,18 @@ import { import type { TransactionMetadataBase } from './metadata' import type { Transaction } from './transaction' -export interface BatchTxn { - OuterAccount: string +export type BatchInnerTransaction = Transaction & { + Fee: '0' - Sequence?: number + SigningPubKey?: '' - TicketSequence?: number + TxnSignature?: '' - BatchIndex: number -} + Signers?: never -export type BatchInnerTransaction = Transaction & { - BatchTxn?: BatchTxn + LastLedgerSequence?: never + + NetworkID?: never } export interface BatchSigner { diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index feaaf7eb52..6f6a995b25 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -242,8 +242,13 @@ export function validateOptionalField( /* eslint-enable @typescript-eslint/restrict-template-expressions -- checked before */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface -- no global flags right now, so this is fine -export interface GlobalFlags {} +export enum GlobalFlags { + tfInnerBatchTxn = 0x40000000, +} + +export interface GlobalFlagsInterface { + tfInnerBatchTxn?: boolean +} /** * Every transaction has the same set of common fields. @@ -276,7 +281,7 @@ export interface BaseTransaction { */ AccountTxnID?: string /** Set of bit-flags for this transaction. */ - Flags?: number | GlobalFlags + Flags?: number | GlobalFlagsInterface /** * Highest ledger index this transaction can appear in. Specifying this field * places a strict upper limit on how long the transaction can wait to be diff --git a/packages/xrpl/src/models/transactions/offerCreate.ts b/packages/xrpl/src/models/transactions/offerCreate.ts index 782e635499..5870730e6a 100644 --- a/packages/xrpl/src/models/transactions/offerCreate.ts +++ b/packages/xrpl/src/models/transactions/offerCreate.ts @@ -3,7 +3,7 @@ import { Amount } from '../common' import { BaseTransaction, - GlobalFlags, + GlobalFlagsInterface, validateBaseTransaction, isAmount, } from './common' @@ -78,7 +78,7 @@ export enum OfferCreateFlags { * // } * ``` */ -export interface OfferCreateFlagsInterface extends GlobalFlags { +export interface OfferCreateFlagsInterface extends GlobalFlagsInterface { tfPassive?: boolean tfImmediateOrCancel?: boolean tfFillOrKill?: boolean diff --git a/packages/xrpl/src/models/transactions/payment.ts b/packages/xrpl/src/models/transactions/payment.ts index 91d0b86c47..3bef4da84e 100644 --- a/packages/xrpl/src/models/transactions/payment.ts +++ b/packages/xrpl/src/models/transactions/payment.ts @@ -5,7 +5,7 @@ import { isFlagEnabled } from '../utils' import { BaseTransaction, isAmount, - GlobalFlags, + GlobalFlagsInterface, validateBaseTransaction, isAccount, validateRequiredField, @@ -82,7 +82,7 @@ export enum PaymentFlags { * // } * ``` */ -export interface PaymentFlagsInterface extends GlobalFlags { +export interface PaymentFlagsInterface extends GlobalFlagsInterface { /** * Do not use the default path; only use paths included in the Paths field. * This is intended to force the transaction to take arbitrage opportunities. diff --git a/packages/xrpl/src/models/transactions/paymentChannelClaim.ts b/packages/xrpl/src/models/transactions/paymentChannelClaim.ts index c673f181bc..5fb6e1edec 100644 --- a/packages/xrpl/src/models/transactions/paymentChannelClaim.ts +++ b/packages/xrpl/src/models/transactions/paymentChannelClaim.ts @@ -1,6 +1,10 @@ import { ValidationError } from '../../errors' -import { BaseTransaction, GlobalFlags, validateBaseTransaction } from './common' +import { + BaseTransaction, + GlobalFlagsInterface, + validateBaseTransaction, +} from './common' /** * Enum representing values for PaymentChannelClaim transaction flags. @@ -67,7 +71,8 @@ export enum PaymentChannelClaimFlags { * // } * ``` */ -export interface PaymentChannelClaimFlagsInterface extends GlobalFlags { +export interface PaymentChannelClaimFlagsInterface + extends GlobalFlagsInterface { /** * Clear the channel's Expiration time. (Expiration is different from the * channel's immutable CancelAfter time.) Only the source address of the diff --git a/packages/xrpl/src/models/transactions/trustSet.ts b/packages/xrpl/src/models/transactions/trustSet.ts index f584261af3..e05d091e3e 100644 --- a/packages/xrpl/src/models/transactions/trustSet.ts +++ b/packages/xrpl/src/models/transactions/trustSet.ts @@ -3,7 +3,7 @@ import { IssuedCurrencyAmount } from '../common' import { BaseTransaction, - GlobalFlags, + GlobalFlagsInterface, isAmount, validateBaseTransaction, } from './common' @@ -72,7 +72,7 @@ export enum TrustSetFlags { * // } * ``` */ -export interface TrustSetFlagsInterface extends GlobalFlags { +export interface TrustSetFlagsInterface extends GlobalFlagsInterface { /** * Authorize the other party to hold currency issued by this account. (No * effect unless using the asfRequireAuth AccountSet flag.) Cannot be unset. diff --git a/packages/xrpl/src/models/utils/flags.ts b/packages/xrpl/src/models/utils/flags.ts index 81fba1aee7..d0153da102 100644 --- a/packages/xrpl/src/models/utils/flags.ts +++ b/packages/xrpl/src/models/utils/flags.ts @@ -8,7 +8,7 @@ import { import { AccountSetTfFlags } from '../transactions/accountSet' import { AMMDepositFlags } from '../transactions/AMMDeposit' import { AMMWithdrawFlags } from '../transactions/AMMWithdraw' -import { GlobalFlags } from '../transactions/common' +import { GlobalFlagsInterface } from '../transactions/common' import { NFTokenCreateOfferFlags } from '../transactions/NFTokenCreateOffer' import { NFTokenMintFlags } from '../transactions/NFTokenMint' import { OfferCreateFlags } from '../transactions/offerCreate' @@ -76,16 +76,17 @@ export function setTransactionFlagsToNumber(tx: Transaction): void { : 0 } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -- added ValidationError check for flagEnum -function convertFlagsToNumber(flags: GlobalFlags, flagEnum: any): number { +function convertFlagsToNumber( + flags: GlobalFlagsInterface, + flagEnum: object, +): number { return Object.keys(flags).reduce((resultFlags, flag) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- safe member access if (flagEnum[flag] == null) { throw new ValidationError( `flag ${flag} doesn't exist in flagEnum: ${JSON.stringify(flagEnum)}`, ) } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- safe member access + return flags[flag] ? resultFlags | flagEnum[flag] : resultFlags }, 0) } diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 8ced19035f..c213af2d76 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -6,7 +6,7 @@ import { type Client } from '..' import { ValidationError, XrplError } from '../errors' import { AccountInfoRequest, AccountObjectsRequest } from '../models/methods' import { Batch, Payment, Transaction } from '../models/transactions' -import { BatchTxn } from '../models/transactions/batch' +import { GlobalFlags } from '../models/transactions/common' import { xrpToDrops } from '../utils' import { hashSignedTx } from '../utils/hashes' @@ -407,7 +407,7 @@ export function handleDeliverMax(tx: Payment): void { } /** - * Autofills all the relevant `BatchTxn` fields. + * Autofills all the relevant `x` fields. * * @param client - The client object. * @param tx - The transaction object. @@ -417,31 +417,40 @@ export async function autofillBatchTxn( client: Client, tx: Batch, ): Promise { - const accountSequences: Record = {} - let batchIndex = 0 + const accountSequences: Record = { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- filled in earlier in autofill + [tx.Account]: tx.Sequence as number, + } const txIds: string[] = [] for await (const rawTxn of tx.RawTransactions) { const txn = rawTxn.RawTransaction - if (txn.BatchTxn !== undefined) { - // eslint-disable-next-line no-continue -- this is fine - continue + + // Flag processing + /* eslint-disable no-bitwise -- needed here for flag parsing */ + if (txn.Flags == null) { + txn.Flags = GlobalFlags.tfInnerBatchTxn + } else if (typeof txn.Flags === 'number') { + if (!((txn.Flags & GlobalFlags.tfInnerBatchTxn) === 0)) { + txn.Flags |= GlobalFlags.tfInnerBatchTxn + } + } else if (!txn.Flags.tfInnerBatchTxn) { + txn.Flags.tfInnerBatchTxn = true } - const batchTxn: Partial = {} - batchTxn.OuterAccount = tx.Account - - if (txn.Account in accountSequences) { - batchTxn.Sequence = accountSequences[txn.Account] - accountSequences[txn.Account] += 1 - } else { - const sequence = await getNextValidSequenceNumber(client, txn.Account) - accountSequences[txn.Account] = sequence + 1 - batchTxn.Sequence = sequence + /* eslint-enable no-bitwise */ + + // Sequence processing + if (txn.Sequence == null && txn.TicketSequence == null) { + if (txn.Account in accountSequences) { + txn.Sequence = accountSequences[txn.Account] + accountSequences[txn.Account] += 1 + } else { + const sequence = await getNextValidSequenceNumber(client, txn.Account) + accountSequences[txn.Account] = sequence + 1 + txn.Sequence = sequence + } } - batchTxn.BatchIndex = batchIndex - batchIndex += 1 - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - txn.BatchTxn = batchTxn as BatchTxn + txIds.push(hashSignedTx(txn)) } if (tx.TxIDs == null) { From 39c7ef576e2b24ee3bb96a076b2682c2501ff828 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 7 Nov 2024 13:36:22 -0500 Subject: [PATCH 30/73] replace BatchTxn in some more places, fix tests --- packages/xrpl/src/Wallet/index.ts | 5 ++- .../xrpl/src/models/transactions/batch.ts | 2 +- packages/xrpl/src/models/utils/flags.ts | 23 +++++++++- packages/xrpl/src/sugar/autofill.ts | 5 +-- packages/xrpl/src/utils/hashes/hashLedger.ts | 8 ++-- packages/xrpl/test/client/autofill.test.ts | 31 ++++++------- packages/xrpl/test/utils/hashes.test.ts | 11 ++--- packages/xrpl/test/wallet/batchSigner.test.ts | 45 +++++-------------- 8 files changed, 57 insertions(+), 73 deletions(-) diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index 93998633c9..e5f801bceb 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -24,6 +24,8 @@ import { import ECDSA from '../ECDSA' import { ValidationError } from '../errors' import { Transaction, validate } from '../models/transactions' +import { GlobalFlags } from '../models/transactions/common' +import { hasFlag } from '../models/utils/flags' import { ensureClassicAddress } from '../sugar/utils' import { omitBy } from '../utils/collections' import { hashSignedTx } from '../utils/hashes/hashLedger' @@ -407,8 +409,7 @@ export class Wallet { */ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type validate(tx as unknown as Record) - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- needed here for JS validation - if ((tx as unknown as Record).BatchTxn != null) { + if (hasFlag(tx, GlobalFlags.tfInnerBatchTxn)) { throw new ValidationError('Cannot sign a Batch inner transaction.') } diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index 6c848a35e6..f6745d5c05 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -14,7 +14,7 @@ import type { TransactionMetadataBase } from './metadata' import type { Transaction } from './transaction' export type BatchInnerTransaction = Transaction & { - Fee: '0' + Fee?: '0' SigningPubKey?: '' diff --git a/packages/xrpl/src/models/utils/flags.ts b/packages/xrpl/src/models/utils/flags.ts index d0153da102..fd3e46c025 100644 --- a/packages/xrpl/src/models/utils/flags.ts +++ b/packages/xrpl/src/models/utils/flags.ts @@ -8,7 +8,7 @@ import { import { AccountSetTfFlags } from '../transactions/accountSet' import { AMMDepositFlags } from '../transactions/AMMDeposit' import { AMMWithdrawFlags } from '../transactions/AMMWithdraw' -import { GlobalFlagsInterface } from '../transactions/common' +import { GlobalFlags, GlobalFlagsInterface } from '../transactions/common' import { NFTokenCreateOfferFlags } from '../transactions/NFTokenCreateOffer' import { NFTokenMintFlags } from '../transactions/NFTokenMint' import { OfferCreateFlags } from '../transactions/offerCreate' @@ -117,3 +117,24 @@ export function parseTransactionFlags(tx: Transaction): object { return flagsMap } + +/** + * Determines whether a transaction has a certain flag enabled. + * + * @param tx The transaction. + * @param flag The flag to check. + * @returns Whether `flag` is enabled on `tx`. + */ +export function hasFlag(tx: Transaction, flag: number): boolean { + if (tx.Flags == null) { + return false + } + if (typeof tx.Flags === 'number') { + return isFlagEnabled(tx.Flags, flag) + } + const txFlagNum = convertFlagsToNumber( + tx.Flags, + txToFlag[tx.TransactionType] ?? GlobalFlags, + ) + return isFlagEnabled(txFlagNum, flag) +} diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index c213af2d76..966eb10f6b 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -417,10 +417,7 @@ export async function autofillBatchTxn( client: Client, tx: Batch, ): Promise { - const accountSequences: Record = { - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- filled in earlier in autofill - [tx.Account]: tx.Sequence as number, - } + const accountSequences: Record = {} const txIds: string[] = [] for await (const rawTxn of tx.RawTransactions) { diff --git a/packages/xrpl/src/utils/hashes/hashLedger.ts b/packages/xrpl/src/utils/hashes/hashLedger.ts index c6dcdf39c2..0788e1ee4d 100644 --- a/packages/xrpl/src/utils/hashes/hashLedger.ts +++ b/packages/xrpl/src/utils/hashes/hashLedger.ts @@ -12,6 +12,8 @@ import { APIVersion } from '../../models' import { LedgerEntry } from '../../models/ledger' import { LedgerVersionMap } from '../../models/ledger/Ledger' import { Transaction, TransactionMetadata } from '../../models/transactions' +import { GlobalFlags } from '../../models/transactions/common' +import { hasFlag } from '../../models/utils/flags' import HashPrefix from './HashPrefix' import sha512Half from './sha512Half' @@ -66,7 +68,7 @@ function addLengthPrefix(hex: string): string { * * @param tx - A transaction to hash. Tx may be in binary blob form. Tx must be signed. * @returns A hash of tx. - * @throws ValidationError if the Transaction is unsigned.\ + * @throws ValidationError if the Transaction is unsigned. * @category Utilities */ export function hashSignedTx(tx: Transaction | string): string { @@ -85,9 +87,7 @@ export function hashSignedTx(tx: Transaction | string): string { txObject.TxnSignature === undefined && txObject.Signers === undefined && txObject.SigningPubKey === undefined && - // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- exception needed here - // @ts-expect-error -- needed here for Batch transactions - txObject.BatchTxn === undefined + !hasFlag(txObject, GlobalFlags.tfInnerBatchTxn) ) { throw new ValidationError('The transaction must be signed to hash it.') } diff --git a/packages/xrpl/test/client/autofill.test.ts b/packages/xrpl/test/client/autofill.test.ts index 639ff21d15..0b400803cc 100644 --- a/packages/xrpl/test/client/autofill.test.ts +++ b/packages/xrpl/test/client/autofill.test.ts @@ -6,6 +6,7 @@ import { EscrowFinish, Payment, Transaction, + Batch, } from '../../src' import { ValidationError } from '../../src/errors' import rippled from '../fixtures/rippled' @@ -437,13 +438,14 @@ describe('client.autofill', function () { }) it('should autofill Batch transaction with single account', async function () { - const tx: Transaction = { + const tx: Batch = { TransactionType: 'Batch', Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', RawTransactions: [ { RawTransaction: { TransactionType: 'DepositPreauth', + Flags: 0x40000000, Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', }, @@ -451,6 +453,7 @@ describe('client.autofill', function () { { RawTransaction: { TransactionType: 'DepositPreauth', + Flags: 0x40000000, Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', Authorize: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', }, @@ -472,21 +475,16 @@ describe('client.autofill', function () { const txResult = await testContext.client.autofill(tx) txResult.RawTransactions.forEach((rawTxOuter, index) => { const rawTx = rawTxOuter.RawTransaction - assert.strictEqual( - rawTx.BatchTxn?.OuterAccount, - 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', - ) - assert.strictEqual(rawTx.BatchTxn?.Sequence, 23 + index) - assert.strictEqual(rawTx.BatchTxn?.BatchIndex, index) + assert.strictEqual(rawTx.Sequence, 23 + index) }) assert.strictEqual(txResult.TxIDs?.length, 2) assert.strictEqual( txResult.TxIDs?.[0], - 'A63E4FBFADA7A0504F1307F4ADBEDDE70A81C9EFB21D12B6C2824DF21D08862B', + 'EABF5CC759AECF2AA7E862F884DC119CEBAD1F8083E70DDD20B52F59E0E32E62', ) assert.strictEqual( txResult.TxIDs?.[1], - 'B2A225765BEA821FC074CA0BB803C3BE7B341F801369CF30806DA8CF5D9C0CAB', + '79C2CE60E79BDF5C702F9A60B2747699C28D62AED6D0C900765AF2BD1F4BDB3F', ) }) @@ -498,6 +496,7 @@ describe('client.autofill', function () { { RawTransaction: { TransactionType: 'DepositPreauth', + Flags: 0x40000000, Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', }, @@ -505,6 +504,7 @@ describe('client.autofill', function () { { RawTransaction: { TransactionType: 'DepositPreauth', + Flags: 0x40000000, Account: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', }, @@ -524,23 +524,18 @@ describe('client.autofill', function () { }, }) const txResult = await testContext.client.autofill(tx) - txResult.RawTransactions.forEach((rawTxOuter, index) => { + txResult.RawTransactions.forEach((rawTxOuter) => { const rawTx = rawTxOuter.RawTransaction - assert.strictEqual( - rawTx.BatchTxn?.OuterAccount, - 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', - ) - assert.strictEqual(rawTx.BatchTxn?.Sequence, 23) - assert.strictEqual(rawTx.BatchTxn?.BatchIndex, index) + assert.strictEqual(rawTx.Sequence, 23) }) assert.strictEqual(txResult.TxIDs?.length, 2) assert.strictEqual( txResult.TxIDs?.[0], - 'A63E4FBFADA7A0504F1307F4ADBEDDE70A81C9EFB21D12B6C2824DF21D08862B', + 'EABF5CC759AECF2AA7E862F884DC119CEBAD1F8083E70DDD20B52F59E0E32E62', ) assert.strictEqual( txResult.TxIDs?.[1], - '8C233D6C1394812AFA969E1B91D02F31F35E0D3D813C1DCAFB955E4957FF22D9', + 'E2AAB1C1AD462BBC71FBEA4380139D68B5A76C6B30DA7A96C485BBD9931C2F5D', ) }) }) diff --git a/packages/xrpl/test/utils/hashes.test.ts b/packages/xrpl/test/utils/hashes.test.ts index cd6312f209..edc19575fa 100644 --- a/packages/xrpl/test/utils/hashes.test.ts +++ b/packages/xrpl/test/utils/hashes.test.ts @@ -217,22 +217,17 @@ describe('Hashes', function () { const transaction: BatchInnerTransaction = { Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', Amount: '1000000', - BatchTxn: { - BatchIndex: 0, - OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', - Sequence: 470, - }, Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', Fee: '0', - NetworkID: 21336, - Sequence: 0, + Flags: 0x40000000, + Sequence: 470, SigningPubKey: '', TransactionType: 'Payment', } assert.equal( hashSignedTx(transaction), - '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', + '9EDF5DB29F536DD3919037F1E8A72B040D075571A10C9000294C57B5ECEEA791', ) }) }) diff --git a/packages/xrpl/test/wallet/batchSigner.test.ts b/packages/xrpl/test/wallet/batchSigner.test.ts index 782c72f24b..25320afddd 100644 --- a/packages/xrpl/test/wallet/batchSigner.test.ts +++ b/packages/xrpl/test/wallet/batchSigner.test.ts @@ -42,16 +42,11 @@ describe('Wallet batch operations', function () { { RawTransaction: { Account: 'rJy554HmWFFJQGnRfZuoo8nV97XSMq77h7', + Flags: 0x40000000, Amount: '5000000', - BatchTxn: { - BatchIndex: 1, - OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', - Sequence: 215, - }, Destination: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', Fee: '0', - NetworkID: 21336, - Sequence: 0, + Sequence: 215, SigningPubKey: '', TransactionType: 'Payment', }, @@ -59,16 +54,11 @@ describe('Wallet batch operations', function () { { RawTransaction: { Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Flags: 0x40000000, Amount: '1000000', - BatchTxn: { - BatchIndex: 0, - OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', - Sequence: 470, - }, Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', Fee: '0', - NetworkID: 21336, - Sequence: 0, + Sequence: 470, SigningPubKey: '', TransactionType: 'Payment', }, @@ -142,16 +132,11 @@ describe('Wallet batch operations', function () { { RawTransaction: { Account: 'rJy554HmWFFJQGnRfZuoo8nV97XSMq77h7', + Flags: 0x40000000, Amount: '5000000', - BatchTxn: { - BatchIndex: 1, - OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', - Sequence: 215, - }, Destination: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', Fee: '0', - NetworkID: 21336, - Sequence: 0, + Sequence: 215, SigningPubKey: '', TransactionType: 'Payment', }, @@ -159,16 +144,11 @@ describe('Wallet batch operations', function () { { RawTransaction: { Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Flags: 0x40000000, Amount: '1000000', - BatchTxn: { - BatchIndex: 0, - OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', - Sequence: 470, - }, Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', Fee: '0', - NetworkID: 21336, - Sequence: 0, + Sequence: 470, SigningPubKey: '', TransactionType: 'Payment', }, @@ -212,15 +192,10 @@ describe('Wallet batch operations', function () { RawTransaction: { Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', Amount: '1000000', - BatchTxn: { - BatchIndex: 0, - OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', - Sequence: 470, - }, Destination: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', Fee: '0', - NetworkID: 21336, - Sequence: 0, + Flags: 0x40000000, + Sequence: 470, SigningPubKey: '', TransactionType: 'Payment', }, From 39035993ab82e8234252161f2f51ed1995a269c1 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 7 Nov 2024 13:41:40 -0500 Subject: [PATCH 31/73] fix linter issues --- packages/xrpl/src/client/connection.ts | 1 - packages/xrpl/src/sugar/submit.ts | 1 - packages/xrpl/test/integration/submitAndWait.test.ts | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/xrpl/src/client/connection.ts b/packages/xrpl/src/client/connection.ts index 3214b557e2..7173bc45c3 100644 --- a/packages/xrpl/src/client/connection.ts +++ b/packages/xrpl/src/client/connection.ts @@ -349,7 +349,6 @@ export class Connection extends EventEmitter { try { this.requestManager.handleResponse(data) } catch (error) { - // eslint-disable-next-line max-depth -- okay here if (error instanceof Error) { this.emit('error', 'badMessage', error.message, message) } else { diff --git a/packages/xrpl/src/sugar/submit.ts b/packages/xrpl/src/sugar/submit.ts index 423a863cf8..c876bf98ee 100644 --- a/packages/xrpl/src/sugar/submit.ts +++ b/packages/xrpl/src/sugar/submit.ts @@ -176,7 +176,6 @@ function isSigned(transaction: SubmittableTransaction | string): boolean { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- we know that tx.Signers is an array of Signers const signers = tx.Signers as Signer[] for (const signer of signers) { - // eslint-disable-next-line max-depth -- necessary for checking if signer is signed if ( // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- necessary check signer.Signer.SigningPubKey == null || diff --git a/packages/xrpl/test/integration/submitAndWait.test.ts b/packages/xrpl/test/integration/submitAndWait.test.ts index bae32f7d0c..7d1b3a3982 100644 --- a/packages/xrpl/test/integration/submitAndWait.test.ts +++ b/packages/xrpl/test/integration/submitAndWait.test.ts @@ -59,7 +59,6 @@ describe('client.submitAndWait', function () { retries = 0 break } catch (err) { - // eslint-disable-next-line max-depth -- Necessary if (!(err instanceof Error)) { throw err } @@ -69,7 +68,7 @@ describe('client.submitAndWait', function () { const errorCode = matches?.groups?.errorCode // Retry if another transaction finished before this one - // eslint-disable-next-line max-depth -- Testing + if (['tefPAST_SEQ', 'tefMAX_LEDGER'].includes(errorCode || '')) { // eslint-disable-next-line no-await-in-loop, no-promise-executor-return -- We are waiting on retries await new Promise((resolve) => setTimeout(resolve, 1000)) From ec244180fd76072627299c92b648e6e214ba0929 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 7 Nov 2024 16:46:46 -0500 Subject: [PATCH 32/73] update definitions --- .vscode/settings.json | 4 +- .../src/enums/definitions.json | 40 +++++-------------- packages/xrpl/src/sugar/submit.ts | 2 +- 3 files changed, 14 insertions(+), 32 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 787ced320d..6e4555a206 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,7 @@ "altnet", "Autofills", "Batchnet", + "bignumber", "Clawback", "hostid", "keypair", @@ -16,7 +17,8 @@ "secp256k1", "Setf", "Sidechains", - "xchain" + "xchain", + "xrplf" ], "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode", diff --git a/packages/ripple-binary-codec/src/enums/definitions.json b/packages/ripple-binary-codec/src/enums/definitions.json index 07d56e5b54..c7b02b0370 100644 --- a/packages/ripple-binary-codec/src/enums/definitions.json +++ b/packages/ripple-binary-codec/src/enums/definitions.json @@ -260,16 +260,6 @@ "type": "UInt8" } ], - [ - "BatchIndex", - { - "nth": 20, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt8" - } - ], [ "LedgerEntryType", { @@ -2003,7 +1993,7 @@ [ "InnerResult", { - "nth": 30, + "nth": 32, "isVLEncoded": true, "isSerialized": true, "isSigningField": true, @@ -2170,16 +2160,6 @@ "type": "AccountID" } ], - [ - "OuterAccount", - { - "nth": 24, - "isVLEncoded": true, - "isSerialized": true, - "isSigningField": true, - "type": "AccountID" - } - ], [ "Indexes", { @@ -2223,7 +2203,7 @@ [ "TxIDs", { - "nth": 5, + "nth": 6, "isVLEncoded": true, "isSerialized": true, "isSigningField": true, @@ -2603,7 +2583,7 @@ [ "RawTransaction", { - "nth": 33, + "nth": 34, "isVLEncoded": false, "isSerialized": true, "isSigningField": true, @@ -2613,7 +2593,7 @@ [ "BatchExecution", { - "nth": 34, + "nth": 35, "isVLEncoded": false, "isSerialized": true, "isSigningField": true, @@ -2623,7 +2603,7 @@ [ "BatchTxn", { - "nth": 35, + "nth": 36, "isVLEncoded": false, "isSerialized": true, "isSigningField": true, @@ -2633,7 +2613,7 @@ [ "BatchSigner", { - "nth": 36, + "nth": 37, "isVLEncoded": false, "isSerialized": true, "isSigningField": true, @@ -2833,7 +2813,7 @@ [ "BatchExecutions", { - "nth": 26, + "nth": 28, "isVLEncoded": false, "isSerialized": true, "isSigningField": true, @@ -2843,7 +2823,7 @@ [ "RawTransactions", { - "nth": 27, + "nth": 29, "isVLEncoded": false, "isSerialized": true, "isSigningField": true, @@ -2853,7 +2833,7 @@ [ "BatchSigners", { - "nth": 28, + "nth": 30, "isVLEncoded": false, "isSerialized": true, "isSigningField": false, @@ -3098,7 +3078,7 @@ "OracleSet": 51, "OracleDelete": 52, "LedgerStateFix": 53, - "Batch": 54, + "Batch": 61, "EnableAmendment": 100, "SetFee": 101, "UNLModify": 102 diff --git a/packages/xrpl/src/sugar/submit.ts b/packages/xrpl/src/sugar/submit.ts index c876bf98ee..547dad77c5 100644 --- a/packages/xrpl/src/sugar/submit.ts +++ b/packages/xrpl/src/sugar/submit.ts @@ -283,7 +283,7 @@ export function getLastLedgerSequence( transaction: Transaction | string, ): number | null { const tx = typeof transaction === 'string' ? decode(transaction) : transaction - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- converts LastLedgSeq to number if present. + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- converts LastLedgerSeq to number if present. return tx.LastLedgerSequence as number | null } From f8376eba2e6b0932f2b2026c99425588157c26e9 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 7 Nov 2024 16:58:31 -0500 Subject: [PATCH 33/73] Batch integration test --- packages/xrpl/src/client/RequestManager.ts | 5 +- .../xrpl/src/models/methods/baseMethod.ts | 1 + .../xrpl/src/models/transactions/batch.ts | 28 +++++++++- packages/xrpl/src/models/utils/flags.ts | 2 + packages/xrpl/src/sugar/autofill.ts | 42 ++++++++++++-- packages/xrpl/test/client/autofill.test.ts | 16 +++--- .../integration/transactions/batch.test.ts | 56 +++++++++++++++++++ 7 files changed, 134 insertions(+), 16 deletions(-) create mode 100644 packages/xrpl/test/integration/transactions/batch.test.ts diff --git a/packages/xrpl/src/client/RequestManager.ts b/packages/xrpl/src/client/RequestManager.ts index 79712140ac..f91ef9c55f 100644 --- a/packages/xrpl/src/client/RequestManager.ts +++ b/packages/xrpl/src/client/RequestManager.ts @@ -175,6 +175,7 @@ export default class RequestManager { * @param response - The response to handle. * @throws ResponseFormatError if the response format is invalid, RippledError if rippled returns an error. */ + // eslint-disable-next-line complexity -- handling a response is complex public handleResponse( response: Partial | ErrorResponse>, ): void { @@ -195,7 +196,9 @@ export default class RequestManager { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We know this must be true const errorResponse = response as Partial const error = new RippledError( - errorResponse.error_message ?? errorResponse.error, + errorResponse.error_message ?? + errorResponse.error_exception ?? + errorResponse.error, errorResponse, ) this.reject(response.id, error) diff --git a/packages/xrpl/src/models/methods/baseMethod.ts b/packages/xrpl/src/models/methods/baseMethod.ts index 85dcf90efb..f264c2bd32 100644 --- a/packages/xrpl/src/models/methods/baseMethod.ts +++ b/packages/xrpl/src/models/methods/baseMethod.ts @@ -53,6 +53,7 @@ export interface ErrorResponse { error: string error_code?: string error_message?: string + error_exception?: string request: Request api_version?: number } diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index f6745d5c05..7038b519f8 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -3,6 +3,7 @@ import { Signer } from '../common' import { BaseTransaction, + GlobalFlagsInterface, isArray, isObject, isString, @@ -13,6 +14,31 @@ import { import type { TransactionMetadataBase } from './metadata' import type { Transaction } from './transaction' +/** + * Enum representing values of {@link Batch} transaction flags. + * + * @category Transaction Flags + */ +export enum BatchFlags { + tfAllOrNothing = 0x00010000, + tfOnlyOne = 0x00020000, + tfUntilFailure = 0x00040000, + tfIndependent = 0x00080000, +} + +/** + * Map of flags to boolean values representing {@link Batch} transaction + * flags. + * + * @category Transaction Flags + */ +export interface BatchFlagsInterface extends GlobalFlagsInterface { + tfAllOrNothing?: boolean + tfOnlyOne?: boolean + tfUntilFailure?: boolean + tfIndependent?: boolean +} + export type BatchInnerTransaction = Transaction & { Fee?: '0' @@ -23,8 +49,6 @@ export type BatchInnerTransaction = Transaction & { Signers?: never LastLedgerSequence?: never - - NetworkID?: never } export interface BatchSigner { diff --git a/packages/xrpl/src/models/utils/flags.ts b/packages/xrpl/src/models/utils/flags.ts index fd3e46c025..2e84759635 100644 --- a/packages/xrpl/src/models/utils/flags.ts +++ b/packages/xrpl/src/models/utils/flags.ts @@ -8,6 +8,7 @@ import { import { AccountSetTfFlags } from '../transactions/accountSet' import { AMMDepositFlags } from '../transactions/AMMDeposit' import { AMMWithdrawFlags } from '../transactions/AMMWithdraw' +import { BatchFlags } from '../transactions/batch' import { GlobalFlags, GlobalFlagsInterface } from '../transactions/common' import { NFTokenCreateOfferFlags } from '../transactions/NFTokenCreateOffer' import { NFTokenMintFlags } from '../transactions/NFTokenMint' @@ -48,6 +49,7 @@ const txToFlag = { AccountSet: AccountSetTfFlags, AMMDeposit: AMMDepositFlags, AMMWithdraw: AMMWithdrawFlags, + Batch: BatchFlags, NFTokenCreateOffer: NFTokenCreateOfferFlags, NFTokenMint: NFTokenMintFlags, OfferCreate: OfferCreateFlags, diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 966eb10f6b..732562e41a 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -285,13 +285,16 @@ export async function calculateFeePerTransactionType( scaleValue(netFeeDrops, 33 + fulfillmentBytesSize / 16), ) baseFee = product.dp(0, BigNumber.ROUND_CEIL) - } - - if ( + } else if ( tx.TransactionType === 'AccountDelete' || tx.TransactionType === 'AMMCreate' ) { baseFee = await fetchAccountDeleteFee(client) + } else if (tx.TransactionType === 'Batch') { + baseFee = BigNumber.sum( + baseFee.times(2), + baseFee.times(tx.RawTransactions.length + (tx.BatchSigners?.length ?? 0)), + ) } /* @@ -413,6 +416,7 @@ export function handleDeliverMax(tx: Payment): void { * @param tx - The transaction object. * @returns A promise that resolves with void if there are no blockers, or rejects with an XrplError if there are blockers. */ +// eslint-disable-next-line complexity, max-lines-per-function, max-statements -- needed here, lots to check export async function autofillBatchTxn( client: Client, tx: Batch, @@ -442,12 +446,42 @@ export async function autofillBatchTxn( txn.Sequence = accountSequences[txn.Account] accountSequences[txn.Account] += 1 } else { - const sequence = await getNextValidSequenceNumber(client, txn.Account) + const nextSequence = await getNextValidSequenceNumber( + client, + txn.Account, + ) + const sequence = + txn.Account === tx.Account ? nextSequence + 1 : nextSequence accountSequences[txn.Account] = sequence + 1 txn.Sequence = sequence } } + if (txn.Fee == null) { + txn.Fee = '0' + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JS check + } else if (txn.Fee !== '0') { + throw new XrplError('Must have fee of `0` in inner Batch transaction.') + } + + if (txn.SigningPubKey == null) { + txn.SigningPubKey = '' + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JS check + } else if (txn.SigningPubKey !== '') { + throw new XrplError('Must have fee of `0` in inner Batch transaction.') + } + + // if (txn.TxnSignature == null) { + // txn.TxnSignature = '' + // // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JS check + // } else if (txn.TxnSignature !== '') { + // throw new XrplError('Must have fee of `0` in inner Batch transaction.') + // } + + if (txn.NetworkID == null) { + txn.NetworkID = txNeedsNetworkID(client) ? client.networkID : undefined + } + txIds.push(hashSignedTx(txn)) } if (tx.TxIDs == null) { diff --git a/packages/xrpl/test/client/autofill.test.ts b/packages/xrpl/test/client/autofill.test.ts index 0b400803cc..7aae268630 100644 --- a/packages/xrpl/test/client/autofill.test.ts +++ b/packages/xrpl/test/client/autofill.test.ts @@ -475,16 +475,16 @@ describe('client.autofill', function () { const txResult = await testContext.client.autofill(tx) txResult.RawTransactions.forEach((rawTxOuter, index) => { const rawTx = rawTxOuter.RawTransaction - assert.strictEqual(rawTx.Sequence, 23 + index) + assert.strictEqual(rawTx.Sequence, 23 + index + 1) }) assert.strictEqual(txResult.TxIDs?.length, 2) assert.strictEqual( txResult.TxIDs?.[0], - 'EABF5CC759AECF2AA7E862F884DC119CEBAD1F8083E70DDD20B52F59E0E32E62', + 'E0EA0CCB12ABC736B7A0757613B2C51A6FB4818B9DBD0678F9DAEB797825ABDE', ) assert.strictEqual( txResult.TxIDs?.[1], - '79C2CE60E79BDF5C702F9A60B2747699C28D62AED6D0C900765AF2BD1F4BDB3F', + '2101F5F58F2FDDBF28530702EAE0F63784752BAD6D690EEFE49577BF4107D2C1', ) }) @@ -524,18 +524,16 @@ describe('client.autofill', function () { }, }) const txResult = await testContext.client.autofill(tx) - txResult.RawTransactions.forEach((rawTxOuter) => { - const rawTx = rawTxOuter.RawTransaction - assert.strictEqual(rawTx.Sequence, 23) - }) + assert.strictEqual(txResult.RawTransactions[0].RawTransaction.Sequence, 24) + assert.strictEqual(txResult.RawTransactions[1].RawTransaction.Sequence, 23) assert.strictEqual(txResult.TxIDs?.length, 2) assert.strictEqual( txResult.TxIDs?.[0], - 'EABF5CC759AECF2AA7E862F884DC119CEBAD1F8083E70DDD20B52F59E0E32E62', + 'E0EA0CCB12ABC736B7A0757613B2C51A6FB4818B9DBD0678F9DAEB797825ABDE', ) assert.strictEqual( txResult.TxIDs?.[1], - 'E2AAB1C1AD462BBC71FBEA4380139D68B5A76C6B30DA7A96C485BBD9931C2F5D', + '5F7DA80D86F1933B08FF6FD68AC21A50C81777D8A05BF015FE64F328FF9DA233', ) }) }) diff --git a/packages/xrpl/test/integration/transactions/batch.test.ts b/packages/xrpl/test/integration/transactions/batch.test.ts new file mode 100644 index 0000000000..eb3f4dcf06 --- /dev/null +++ b/packages/xrpl/test/integration/transactions/batch.test.ts @@ -0,0 +1,56 @@ +import { Batch, Wallet } from '../../../src' +import { BatchFlags } from '../../../src/models/transactions/batch' +import serverUrl from '../serverUrl' +import { + setupClient, + teardownClient, + type XrplIntegrationTestContext, +} from '../setup' +import { generateFundedWallet, testTransaction } from '../utils' + +// how long before each test case times out +const TIMEOUT = 20000 + +describe('Batch', function () { + let testContext: XrplIntegrationTestContext + let destination: Wallet + + beforeAll(async () => { + testContext = await setupClient(serverUrl) + destination = await generateFundedWallet(testContext.client) + }, TIMEOUT) + afterAll(async () => teardownClient(testContext)) + + it( + 'base', + async () => { + const tx: Batch = { + TransactionType: 'Batch', + Account: testContext.wallet.classicAddress, + Flags: BatchFlags.tfAllOrNothing, + RawTransactions: [ + { + RawTransaction: { + TransactionType: 'Payment', + Account: testContext.wallet.classicAddress, + Destination: destination.classicAddress, + Amount: '10000000', + }, + }, + { + RawTransaction: { + TransactionType: 'Payment', + Account: testContext.wallet.classicAddress, + Destination: destination.classicAddress, + Amount: '10000000', + }, + }, + ], + } + const autofilled = await testContext.client.autofill(tx) + console.log(JSON.stringify(autofilled, null, 4)) + await testTransaction(testContext.client, autofilled, testContext.wallet) + }, + TIMEOUT, + ) +}) From 260bc32b25aca77b5596be200d65cc4730bf8bb1 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 7 Nov 2024 17:42:17 -0500 Subject: [PATCH 34/73] remove debug statement --- packages/xrpl/test/integration/transactions/batch.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/xrpl/test/integration/transactions/batch.test.ts b/packages/xrpl/test/integration/transactions/batch.test.ts index eb3f4dcf06..848d22d090 100644 --- a/packages/xrpl/test/integration/transactions/batch.test.ts +++ b/packages/xrpl/test/integration/transactions/batch.test.ts @@ -48,7 +48,6 @@ describe('Batch', function () { ], } const autofilled = await testContext.client.autofill(tx) - console.log(JSON.stringify(autofilled, null, 4)) await testTransaction(testContext.client, autofilled, testContext.wallet) }, TIMEOUT, From bf19d1219a4709d66e0e1c76099f90ba3b032ac0 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Fri, 8 Nov 2024 10:36:32 -0500 Subject: [PATCH 35/73] fix TxnSignature --- .../xrpl/src/models/transactions/batch.ts | 2 +- packages/xrpl/src/sugar/autofill.ts | 23 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index 7038b519f8..e93aeb8040 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -44,7 +44,7 @@ export type BatchInnerTransaction = Transaction & { SigningPubKey?: '' - TxnSignature?: '' + TxnSignature?: never Signers?: never diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 732562e41a..981d1353b7 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -461,22 +461,29 @@ export async function autofillBatchTxn( txn.Fee = '0' // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JS check } else if (txn.Fee !== '0') { - throw new XrplError('Must have fee of `0` in inner Batch transaction.') + throw new XrplError('Must have `Fee of "0" in inner Batch transaction.') } if (txn.SigningPubKey == null) { txn.SigningPubKey = '' // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JS check } else if (txn.SigningPubKey !== '') { - throw new XrplError('Must have fee of `0` in inner Batch transaction.') + throw new XrplError( + 'Must have `SigningPubKey` of "" in inner Batch transaction.', + ) } - // if (txn.TxnSignature == null) { - // txn.TxnSignature = '' - // // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JS check - // } else if (txn.TxnSignature !== '') { - // throw new XrplError('Must have fee of `0` in inner Batch transaction.') - // } + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS + if (txn.TxnSignature != null) { + throw new XrplError( + 'Must not have `TxnSignature` in inner Batch transaction.', + ) + } + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS + if (txn.Signers != null) { + throw new XrplError('Must not have `Signers` in inner Batch transaction.') + } if (txn.NetworkID == null) { txn.NetworkID = txNeedsNetworkID(client) ? client.networkID : undefined From 6b03f9198d4052d457a74e26359e1ed022d8e97d Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Fri, 8 Nov 2024 10:44:56 -0500 Subject: [PATCH 36/73] fix BatchMetadata --- packages/xrpl/src/models/transactions/batch.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index e93aeb8040..325e9a5e4f 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -83,8 +83,6 @@ export interface Batch extends BaseTransaction { export interface BatchMetadata extends TransactionMetadataBase { BatchExecutions: Array<{ - TransactionType: string - InnerResult: string TransactionHash: string From e084f4315199e6d6b21cdcf1d47176a51ca8edbc Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 8 Jan 2025 15:06:35 -0500 Subject: [PATCH 37/73] fix tests --- packages/xrpl/src/Wallet/batchSigner.ts | 12 +++++++----- packages/xrpl/src/models/transactions/batch.ts | 4 ++-- packages/xrpl/src/models/transactions/common.ts | 4 +++- packages/xrpl/src/sugar/autofill.ts | 4 ++-- packages/xrpl/test/client/autofill.test.ts | 12 ++++++------ packages/xrpl/test/models/Batch.test.ts | 10 +++++----- packages/xrpl/test/wallet/batchSigner.test.ts | 12 ++++++++---- 7 files changed, 33 insertions(+), 25 deletions(-) diff --git a/packages/xrpl/src/Wallet/batchSigner.ts b/packages/xrpl/src/Wallet/batchSigner.ts index ce709f1b54..2568bb6d0c 100644 --- a/packages/xrpl/src/Wallet/batchSigner.ts +++ b/packages/xrpl/src/Wallet/batchSigner.ts @@ -50,7 +50,7 @@ export function signMultiBatch( validate(transaction as unknown as Record) const fieldsToSign = { flags: transaction.Flags, - txIDs: transaction.TxIDs, + txIDs: transaction.TransactionIDs, } let batchSigner: BatchSigner if (multisignAddress) { @@ -150,19 +150,21 @@ export function combineBatchSigners( function validateBatchTransactionEquivalence(transactions: Batch[]): void { const exampleTransaction = JSON.stringify({ Flags: transactions[0].Flags, - TxIDs: transactions[0].TxIDs, + TransactionIDs: transactions[0].TransactionIDs, }) if ( transactions .slice(1) .some( (tx) => - JSON.stringify({ Flags: tx.Flags, TxIDs: tx.TxIDs }) !== - exampleTransaction, + JSON.stringify({ + Flags: tx.Flags, + TransactionIDs: tx.TransactionIDs, + }) !== exampleTransaction, ) ) { throw new ValidationError( - 'Flags and TxIDs is not the same for all provided transactions.', + 'Flags and TransactionIDs is not the same for all provided transactions.', ) } } diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index 325e9a5e4f..fe73e746d7 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -78,7 +78,7 @@ export interface Batch extends BaseTransaction { /** * Optional because it can be autofilled. */ - TxIDs?: string[] + TransactionIDs?: string[] } export interface BatchMetadata extends TransactionMetadataBase { @@ -167,5 +167,5 @@ export function validateBatch(tx: Record): void { ) }) - validateOptionalField(tx, 'TxIDs', isArray) + validateOptionalField(tx, 'TransactionIDs', isArray) } diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index 11317f0a1b..e0535ba5dd 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -388,7 +388,9 @@ export function validateBaseTransaction(common: Record): void { } if (!TRANSACTION_TYPES.includes(common.TransactionType)) { - throw new ValidationError('BaseTransaction: Unknown TransactionType') + throw new ValidationError( + `BaseTransaction: Unknown TransactionType ${common.TransactionType}`, + ) } validateRequiredField(common, 'Account', isString) diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 981d1353b7..2c064888d0 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -491,8 +491,8 @@ export async function autofillBatchTxn( txIds.push(hashSignedTx(txn)) } - if (tx.TxIDs == null) { + if (tx.TransactionIDs == null) { // eslint-disable-next-line no-param-reassign -- okay for autofilling - tx.TxIDs = txIds + tx.TransactionIDs = txIds } } diff --git a/packages/xrpl/test/client/autofill.test.ts b/packages/xrpl/test/client/autofill.test.ts index 7aae268630..5c7366276c 100644 --- a/packages/xrpl/test/client/autofill.test.ts +++ b/packages/xrpl/test/client/autofill.test.ts @@ -477,13 +477,13 @@ describe('client.autofill', function () { const rawTx = rawTxOuter.RawTransaction assert.strictEqual(rawTx.Sequence, 23 + index + 1) }) - assert.strictEqual(txResult.TxIDs?.length, 2) + assert.strictEqual(txResult.TransactionIDs?.length, 2) assert.strictEqual( - txResult.TxIDs?.[0], + txResult.TransactionIDs?.[0], 'E0EA0CCB12ABC736B7A0757613B2C51A6FB4818B9DBD0678F9DAEB797825ABDE', ) assert.strictEqual( - txResult.TxIDs?.[1], + txResult.TransactionIDs?.[1], '2101F5F58F2FDDBF28530702EAE0F63784752BAD6D690EEFE49577BF4107D2C1', ) }) @@ -526,13 +526,13 @@ describe('client.autofill', function () { const txResult = await testContext.client.autofill(tx) assert.strictEqual(txResult.RawTransactions[0].RawTransaction.Sequence, 24) assert.strictEqual(txResult.RawTransactions[1].RawTransaction.Sequence, 23) - assert.strictEqual(txResult.TxIDs?.length, 2) + assert.strictEqual(txResult.TransactionIDs?.length, 2) assert.strictEqual( - txResult.TxIDs?.[0], + txResult.TransactionIDs?.[0], 'E0EA0CCB12ABC736B7A0757613B2C51A6FB4818B9DBD0678F9DAEB797825ABDE', ) assert.strictEqual( - txResult.TxIDs?.[1], + txResult.TransactionIDs?.[1], '5F7DA80D86F1933B08FF6FD68AC21A50C81777D8A05BF015FE64F328FF9DA233', ) }) diff --git a/packages/xrpl/test/models/Batch.test.ts b/packages/xrpl/test/models/Batch.test.ts index eee0e839bd..94c5da1024 100644 --- a/packages/xrpl/test/models/Batch.test.ts +++ b/packages/xrpl/test/models/Batch.test.ts @@ -63,7 +63,7 @@ describe('Batch', function () { }, ], TransactionType: 'Batch', - TxIDs: [ + TransactionIDs: [ 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', ], @@ -119,18 +119,18 @@ describe('Batch', function () { ) }) - it('throws w/ invalid TxIDs', function () { - tx.TxIDs = 0 + it('throws w/ invalid TransactionIDs', function () { + tx.TransactionIDs = 0 assert.throws( () => validateBatch(tx), ValidationError, - 'Batch: invalid field TxIDs', + 'Batch: invalid field TransactionIDs', ) assert.throws( () => validate(tx), ValidationError, - 'Batch: invalid field TxIDs', + 'Batch: invalid field TransactionIDs', ) }) }) diff --git a/packages/xrpl/test/wallet/batchSigner.test.ts b/packages/xrpl/test/wallet/batchSigner.test.ts index 25320afddd..be46aea818 100644 --- a/packages/xrpl/test/wallet/batchSigner.test.ts +++ b/packages/xrpl/test/wallet/batchSigner.test.ts @@ -65,7 +65,7 @@ describe('Wallet batch operations', function () { }, ], TransactionType: 'Batch', - TxIDs: [ + TransactionIDs: [ 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', ], @@ -156,7 +156,7 @@ describe('Wallet batch operations', function () { ], Sequence: 215, TransactionType: 'Batch', - TxIDs: [ + TransactionIDs: [ 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', ], @@ -201,12 +201,16 @@ describe('Wallet batch operations', function () { }, } const rawTxs = originalTx.RawTransactions.concat(rawTx3) - const txIds = originalTx.TxIDs?.concat([ + const txIds = originalTx.TransactionIDs?.concat([ hashSignedTx(rawTx3.RawTransaction), ]) // set up all the transactions again (repeat what's done in `beforeEach`) - const newTx = { ...originalTx, RawTransactions: rawTxs, TxIDs: txIds } + const newTx = { + ...originalTx, + RawTransactions: rawTxs, + TransactionIDs: txIds, + } tx1 = { ...newTx } tx2 = { ...newTx } const tx3 = { ...newTx } From 0d08deb5c2f9f4ffe2cf0c0637546fd9d4d5f544 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Fri, 10 Jan 2025 14:19:06 -0500 Subject: [PATCH 38/73] more updates --- packages/xrpl/src/models/transactions/batch.ts | 8 -------- packages/xrpl/src/models/transactions/metadata.ts | 5 ++--- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index fe73e746d7..f38c0d21da 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -81,14 +81,6 @@ export interface Batch extends BaseTransaction { TransactionIDs?: string[] } -export interface BatchMetadata extends TransactionMetadataBase { - BatchExecutions: Array<{ - InnerResult: string - - TransactionHash: string - }> -} - /** * Verify the form and type of a Batch at runtime. * diff --git a/packages/xrpl/src/models/transactions/metadata.ts b/packages/xrpl/src/models/transactions/metadata.ts index 0064898ffe..3d6a6db53c 100644 --- a/packages/xrpl/src/models/transactions/metadata.ts +++ b/packages/xrpl/src/models/transactions/metadata.ts @@ -1,6 +1,5 @@ import { Amount, MPTAmount } from '../common' -import { Batch, BatchMetadata } from './batch' import { BaseTransaction } from './common' import { MPTokenIssuanceCreate, @@ -89,6 +88,8 @@ export interface TransactionMetadataBase { delivered_amount?: Amount | MPTAmount | 'unavailable' TransactionIndex: number TransactionResult: string + + ParentBatchID?: string } export type TransactionMetadata = @@ -104,6 +105,4 @@ export type TransactionMetadata = ? NFTokenCancelOfferMetadata : T extends MPTokenIssuanceCreate ? MPTokenIssuanceCreateMetadata - : T extends Batch - ? BatchMetadata : TransactionMetadataBase From f427bc4582e5ef60ccb1534c1a1279222da21d1c Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Sat, 11 Jan 2025 17:40:11 -0500 Subject: [PATCH 39/73] remove TransactionIDs --- .../src/enums/definitions.json | 44 ++++++++++++------- packages/xrpl/src/Wallet/batchSigner.ts | 31 +++++++------ .../xrpl/src/models/transactions/batch.ts | 8 ---- packages/xrpl/src/sugar/autofill.ts | 8 ---- packages/xrpl/test/client/autofill.test.ts | 18 -------- .../integration/transactions/batch.test.ts | 37 ++++++++++++++++ packages/xrpl/test/models/Batch.test.ts | 23 +--------- packages/xrpl/test/wallet/batchSigner.test.ts | 24 +++------- 8 files changed, 93 insertions(+), 100 deletions(-) diff --git a/packages/ripple-binary-codec/src/enums/definitions.json b/packages/ripple-binary-codec/src/enums/definitions.json index ba8d69f471..92eb5158f6 100644 --- a/packages/ripple-binary-codec/src/enums/definitions.json +++ b/packages/ripple-binary-codec/src/enums/definitions.json @@ -58,7 +58,8 @@ "Oracle": 128, "MPTokenIssuance": 126, "MPToken": 127, - "Credential": 129 + "Credential": 129, + "PermissionedDomain": 130 }, "FIELDS": [ [ @@ -1512,7 +1513,7 @@ } ], [ - "BatchTransactionID", + "DomainID", { "nth": 34, "isVLEncoded": false, @@ -1521,6 +1522,16 @@ "type": "Hash256" } ], + [ + "ParentBatchID", + { + "nth": 35, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "Hash256" + } + ], [ "Number", { @@ -2331,16 +2342,6 @@ "type": "Vector256" } ], - [ - "TransactionIDs", - { - "nth": 6, - "isVLEncoded": true, - "isSerialized": true, - "isSigningField": true, - "type": "Vector256" - } - ], [ "Paths", { @@ -2952,7 +2953,7 @@ } ], [ - "RawTransactions", + "AcceptedCredentials", { "nth": 28, "isVLEncoded": false, @@ -2962,7 +2963,7 @@ } ], [ - "BatchSigners", + "RawTransactions", { "nth": 29, "isVLEncoded": false, @@ -2970,6 +2971,16 @@ "isSigningField": true, "type": "STArray" } + ], + [ + "BatchSigners", + { + "nth": 30, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "STArray" + } ] ], "TRANSACTION_RESULTS": { @@ -3215,7 +3226,10 @@ "CredentialCreate": 58, "CredentialAccept": 59, "CredentialDelete": 60, - "Batch": 61, + "NFTokenModify": 61, + "PermissionedDomainSet": 62, + "PermissionedDomainDelete": 63, + "Batch": 64, "EnableAmendment": 100, "SetFee": 101, "UNLModify": 102 diff --git a/packages/xrpl/src/Wallet/batchSigner.ts b/packages/xrpl/src/Wallet/batchSigner.ts index 2568bb6d0c..9521a9f710 100644 --- a/packages/xrpl/src/Wallet/batchSigner.ts +++ b/packages/xrpl/src/Wallet/batchSigner.ts @@ -7,6 +7,7 @@ import { sign } from 'ripple-keypairs' import { ValidationError } from '../errors' import { Batch, Signer, Transaction, validate } from '../models' import { BatchSigner, validateBatch } from '../models/transactions/batch' +import { hashSignedTx } from '../utils/hashes' import { Wallet } from '.' @@ -50,7 +51,9 @@ export function signMultiBatch( validate(transaction as unknown as Record) const fieldsToSign = { flags: transaction.Flags, - txIDs: transaction.TransactionIDs, + txIDs: transaction.RawTransactions.map((rawTx) => + hashSignedTx(rawTx.RawTransaction), + ), } let batchSigner: BatchSigner if (multisignAddress) { @@ -149,22 +152,24 @@ export function combineBatchSigners( */ function validateBatchTransactionEquivalence(transactions: Batch[]): void { const exampleTransaction = JSON.stringify({ - Flags: transactions[0].Flags, - TransactionIDs: transactions[0].TransactionIDs, + flags: transactions[0].Flags, + transactionIDs: transactions[0].RawTransactions.map((rawTx) => + hashSignedTx(rawTx.RawTransaction), + ), }) if ( - transactions - .slice(1) - .some( - (tx) => - JSON.stringify({ - Flags: tx.Flags, - TransactionIDs: tx.TransactionIDs, - }) !== exampleTransaction, - ) + transactions.slice(1).some( + (tx) => + JSON.stringify({ + flags: tx.Flags, + transactionIDs: tx.RawTransactions.map((rawTx) => + hashSignedTx(rawTx.RawTransaction), + ), + }) !== exampleTransaction, + ) ) { throw new ValidationError( - 'Flags and TransactionIDs is not the same for all provided transactions.', + 'Flags and transaction hashes is not the same for all provided transactions.', ) } } diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index f38c0d21da..4be521bbf0 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -11,7 +11,6 @@ import { validateOptionalField, validateRequiredField, } from './common' -import type { TransactionMetadataBase } from './metadata' import type { Transaction } from './transaction' /** @@ -74,11 +73,6 @@ export interface Batch extends BaseTransaction { RawTransactions: Array<{ RawTransaction: BatchInnerTransaction }> - - /** - * Optional because it can be autofilled. - */ - TransactionIDs?: string[] } /** @@ -158,6 +152,4 @@ export function validateBatch(tx: Record): void { `BatchSigners[${index}].TxnSignature`, ) }) - - validateOptionalField(tx, 'TransactionIDs', isArray) } diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 2c064888d0..3352a74da5 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -8,7 +8,6 @@ import { AccountInfoRequest, AccountObjectsRequest } from '../models/methods' import { Batch, Payment, Transaction } from '../models/transactions' import { GlobalFlags } from '../models/transactions/common' import { xrpToDrops } from '../utils' -import { hashSignedTx } from '../utils/hashes' import getFeeXrp from './getFeeXrp' @@ -422,7 +421,6 @@ export async function autofillBatchTxn( tx: Batch, ): Promise { const accountSequences: Record = {} - const txIds: string[] = [] for await (const rawTxn of tx.RawTransactions) { const txn = rawTxn.RawTransaction @@ -488,11 +486,5 @@ export async function autofillBatchTxn( if (txn.NetworkID == null) { txn.NetworkID = txNeedsNetworkID(client) ? client.networkID : undefined } - - txIds.push(hashSignedTx(txn)) - } - if (tx.TransactionIDs == null) { - // eslint-disable-next-line no-param-reassign -- okay for autofilling - tx.TransactionIDs = txIds } } diff --git a/packages/xrpl/test/client/autofill.test.ts b/packages/xrpl/test/client/autofill.test.ts index 5c7366276c..653c010711 100644 --- a/packages/xrpl/test/client/autofill.test.ts +++ b/packages/xrpl/test/client/autofill.test.ts @@ -477,15 +477,6 @@ describe('client.autofill', function () { const rawTx = rawTxOuter.RawTransaction assert.strictEqual(rawTx.Sequence, 23 + index + 1) }) - assert.strictEqual(txResult.TransactionIDs?.length, 2) - assert.strictEqual( - txResult.TransactionIDs?.[0], - 'E0EA0CCB12ABC736B7A0757613B2C51A6FB4818B9DBD0678F9DAEB797825ABDE', - ) - assert.strictEqual( - txResult.TransactionIDs?.[1], - '2101F5F58F2FDDBF28530702EAE0F63784752BAD6D690EEFE49577BF4107D2C1', - ) }) it('should autofill Batch transaction with single account', async function () { @@ -526,14 +517,5 @@ describe('client.autofill', function () { const txResult = await testContext.client.autofill(tx) assert.strictEqual(txResult.RawTransactions[0].RawTransaction.Sequence, 24) assert.strictEqual(txResult.RawTransactions[1].RawTransaction.Sequence, 23) - assert.strictEqual(txResult.TransactionIDs?.length, 2) - assert.strictEqual( - txResult.TransactionIDs?.[0], - 'E0EA0CCB12ABC736B7A0757613B2C51A6FB4818B9DBD0678F9DAEB797825ABDE', - ) - assert.strictEqual( - txResult.TransactionIDs?.[1], - '5F7DA80D86F1933B08FF6FD68AC21A50C81777D8A05BF015FE64F328FF9DA233', - ) }) }) diff --git a/packages/xrpl/test/integration/transactions/batch.test.ts b/packages/xrpl/test/integration/transactions/batch.test.ts index 848d22d090..f7c810dd58 100644 --- a/packages/xrpl/test/integration/transactions/batch.test.ts +++ b/packages/xrpl/test/integration/transactions/batch.test.ts @@ -1,5 +1,6 @@ import { Batch, Wallet } from '../../../src' import { BatchFlags } from '../../../src/models/transactions/batch' +// import { signMultiBatch } from '../../../src/Wallet/batchSigner' import serverUrl from '../serverUrl' import { setupClient, @@ -14,9 +15,11 @@ const TIMEOUT = 20000 describe('Batch', function () { let testContext: XrplIntegrationTestContext let destination: Wallet + let wallet2: Wallet beforeAll(async () => { testContext = await setupClient(serverUrl) + wallet2 = await generateFundedWallet(testContext.client) destination = await generateFundedWallet(testContext.client) }, TIMEOUT) afterAll(async () => teardownClient(testContext)) @@ -52,4 +55,38 @@ describe('Batch', function () { }, TIMEOUT, ) + + it( + 'batch multisign', + async () => { + const tx: Batch = { + TransactionType: 'Batch', + Account: testContext.wallet.classicAddress, + Flags: BatchFlags.tfAllOrNothing, + Fee: '50', + RawTransactions: [ + { + RawTransaction: { + TransactionType: 'Payment', + Account: testContext.wallet.classicAddress, + Destination: destination.classicAddress, + Amount: '10000000', + }, + }, + { + RawTransaction: { + TransactionType: 'Payment', + Account: wallet2.classicAddress, + Destination: destination.classicAddress, + Amount: '10000000', + }, + }, + ], + } + const autofilled = await testContext.client.autofill(tx) + // signMultiBatch(wallet2, autofilled) + await testTransaction(testContext.client, autofilled, testContext.wallet) + }, + TIMEOUT, + ) }) diff --git a/packages/xrpl/test/models/Batch.test.ts b/packages/xrpl/test/models/Batch.test.ts index 94c5da1024..d6b3245003 100644 --- a/packages/xrpl/test/models/Batch.test.ts +++ b/packages/xrpl/test/models/Batch.test.ts @@ -9,7 +9,7 @@ import { validateBatch } from '../../src/models/transactions/batch' * Providing runtime verification testing for each specific transaction type. */ describe('Batch', function () { - let tx + let tx: any beforeEach(function () { tx = { @@ -63,11 +63,7 @@ describe('Batch', function () { }, ], TransactionType: 'Batch', - TransactionIDs: [ - 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', - '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', - ], - } as any + } }) it('verifies valid Batch', function () { @@ -118,19 +114,4 @@ describe('Batch', function () { 'Batch: invalid field RawTransactions', ) }) - - it('throws w/ invalid TransactionIDs', function () { - tx.TransactionIDs = 0 - - assert.throws( - () => validateBatch(tx), - ValidationError, - 'Batch: invalid field TransactionIDs', - ) - assert.throws( - () => validate(tx), - ValidationError, - 'Batch: invalid field TransactionIDs', - ) - }) }) diff --git a/packages/xrpl/test/wallet/batchSigner.test.ts b/packages/xrpl/test/wallet/batchSigner.test.ts index be46aea818..cf86f807eb 100644 --- a/packages/xrpl/test/wallet/batchSigner.test.ts +++ b/packages/xrpl/test/wallet/batchSigner.test.ts @@ -8,8 +8,10 @@ import { ValidationError, Wallet, } from '../../src' -import { BatchInnerTransaction } from '../../src/models/transactions/batch' -import { hashSignedTx } from '../../src/utils/hashes' +import { + BatchInnerTransaction, + BatchSigner, +} from '../../src/models/transactions/batch' import { combineBatchSigners, signMultiBatch, @@ -65,10 +67,6 @@ describe('Wallet batch operations', function () { }, ], TransactionType: 'Batch', - TransactionIDs: [ - 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', - '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', - ], } }) it('succeeds with secp256k1 seed', function () { @@ -80,7 +78,7 @@ describe('Wallet batch operations', function () { SigningPubKey: '02691AC5AE1C4C333AE5DF8A93BDC495F0EEBFC6DB0DA7EB6EF808F3AFC006E3FE', TxnSignature: - '30450221008E595499C334127A23190F61FB9ADD8B8C501D543E37945B11FABB66B097A6130220138C908E8C4929B47E994A46D611FAC17AB295CFB8D9E0828B32F2947B97394B', + '304402207E8238D3D2B24B98BA925D69DDAFA3E7D07F85C8ABF1C040B3D1BEBE2C36E92B02200C122F7F3F86AB8FF89207539CAFB4613D665FF336796F99283ED94C66FB3094', }, }, ] @@ -100,7 +98,7 @@ describe('Wallet batch operations', function () { SigningPubKey: 'ED3CC3D14FD80C213BC92A98AFE13A405A030F845EDCFD5E395286A6E9E62BA638', TxnSignature: - 'E3337EE8C746523B5F96BEBE1190164B8B384EE2DC99F327D95ABC14E27F3AE16CC00DA7D61FC535DBFF0ADA3AF06394F8A703EE952A141BD871B75166C5CD0A', + '744FF09C11399F3AC1484F909A92F2D836EA979CB7655BC8F6BC3793F18892F92A16FE41C60EDCD6C2B757FF85D179F1589824ECA397EEA208B94C9D108CDF0A', }, }, ] @@ -156,12 +154,8 @@ describe('Wallet batch operations', function () { ], Sequence: 215, TransactionType: 'Batch', - TransactionIDs: [ - 'ABE4871E9083DF66727045D49DEEDD3A6F166EB7F8D1E92FE868F02E76B2C5CA', - '795AAC88B59E95C3497609749127E69F12958BC016C600C770AEEB1474C840B4', - ], } - let expectedValid + let expectedValid: BatchSigner[] beforeEach(() => { tx1 = { ...originalTx } @@ -201,15 +195,11 @@ describe('Wallet batch operations', function () { }, } const rawTxs = originalTx.RawTransactions.concat(rawTx3) - const txIds = originalTx.TransactionIDs?.concat([ - hashSignedTx(rawTx3.RawTransaction), - ]) // set up all the transactions again (repeat what's done in `beforeEach`) const newTx = { ...originalTx, RawTransactions: rawTxs, - TransactionIDs: txIds, } tx1 = { ...newTx } tx2 = { ...newTx } From 2280b9513b4f67f700b7542fa38e9e89af62f962 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Sat, 11 Jan 2025 18:55:39 -0500 Subject: [PATCH 40/73] add more tests --- packages/ripple-binary-codec/HISTORY.md | 4 +- packages/xrpl/src/Wallet/batchSigner.ts | 30 ++++---- .../xrpl/src/models/transactions/batch.ts | 68 +++++++---------- .../xrpl/src/models/transactions/common.ts | 32 ++++---- .../integration/transactions/batch.test.ts | 28 ++++++- packages/xrpl/test/models/Batch.test.ts | 63 +++++++++------- packages/xrpl/test/testUtils.ts | 23 +++++- packages/xrpl/test/wallet/batchSigner.test.ts | 74 ++++++++++++++++++- 8 files changed, 216 insertions(+), 106 deletions(-) diff --git a/packages/ripple-binary-codec/HISTORY.md b/packages/ripple-binary-codec/HISTORY.md index de801c992a..fd85599457 100644 --- a/packages/ripple-binary-codec/HISTORY.md +++ b/packages/ripple-binary-codec/HISTORY.md @@ -2,11 +2,13 @@ ## Unreleased +### Added +* Support for the `Batch` amendment (XLS-56). + ## 2.2.0 (2024-12-23) ### Added * Support for the Multi-Purpose Token amendment (XLS-33). -* Support for the `Batch` amendment (XLS-56). ## 2.1.0 (2024-06-03) diff --git a/packages/xrpl/src/Wallet/batchSigner.ts b/packages/xrpl/src/Wallet/batchSigner.ts index 9521a9f710..12b6df40f4 100644 --- a/packages/xrpl/src/Wallet/batchSigner.ts +++ b/packages/xrpl/src/Wallet/batchSigner.ts @@ -31,6 +31,12 @@ export function signMultiBatch( } else if (multisign) { multisignAddress = wallet.classicAddress } + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS + if (transaction.TransactionType !== 'Batch') { + throw new ValidationError('Must be a Batch transaction.') + } + const involvedAccounts = transaction.RawTransactions.map( (raw) => raw.RawTransaction.Account, ) @@ -39,11 +45,6 @@ export function signMultiBatch( 'Must be signing for an address included in the Batch.', ) } - - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS - if (transaction.TransactionType !== 'Batch') { - throw new ValidationError('Must be a Batch transaction.') - } /* * This will throw a more clear error for JS users if the supplied transaction has incorrect formatting */ @@ -104,14 +105,12 @@ export function combineBatchSigners( transactions: Array, ): string { if (transactions.length === 0) { - throw new ValidationError('There were 0 transactions to combine.') + throw new ValidationError('There are 0 transactions to combine.') } - const decodedTransactions: Transaction[] = transactions.map( - (txOrBlob: string | Transaction) => { - return getDecodedTransaction(txOrBlob) - }, - ) + const decodedTransactions: Transaction[] = transactions.map((txOrBlob) => { + return getDecodedTransaction(txOrBlob) + }) decodedTransactions.forEach((tx) => { if (tx.TransactionType !== 'Batch') { @@ -128,11 +127,8 @@ export function combineBatchSigners( ) } - if ( - tx.SigningPubKey !== '' && - (tx.TxnSignature != null || tx.Signers != null) - ) { - throw new ValidationError('Transaction must be unsigned.') + if (tx.TxnSignature != null || tx.Signers != null) { + throw new ValidationError('Batch transaction must be unsigned.') } }) @@ -169,7 +165,7 @@ function validateBatchTransactionEquivalence(transactions: Batch[]): void { ) ) { throw new ValidationError( - 'Flags and transaction hashes is not the same for all provided transactions.', + 'Flags and transaction hashes are not the same for all provided transactions.', ) } } diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index 4be521bbf0..1e589b3ddc 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -11,7 +11,7 @@ import { validateOptionalField, validateRequiredField, } from './common' -import type { Transaction } from './transaction' +import type { SubmittableTransaction } from './transaction' /** * Enum representing values of {@link Batch} transaction flags. @@ -38,7 +38,7 @@ export interface BatchFlagsInterface extends GlobalFlagsInterface { tfIndependent?: boolean } -export type BatchInnerTransaction = Transaction & { +export type BatchInnerTransaction = SubmittableTransaction & { Fee?: '0' SigningPubKey?: '' @@ -90,26 +90,22 @@ export function validateBatch(tx: Record): void { const rawTransactions = tx.RawTransactions as unknown[] rawTransactions.forEach((field, index) => { if (!isObject(field)) { - throw new ValidationError(`Batch: RawTransactions[${index} is not object`) + throw new ValidationError( + `Batch: RawTransactions[${index}] is not object`, + ) } // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above const fieldObject = field as Record - validateRequiredField( - fieldObject, - 'RawTransaction', - isObject, - `RawTransactions[${index}].RawTransaction`, - ) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- needed here - // @ts-expect-error -- checked above + validateRequiredField(fieldObject, 'RawTransaction', isObject, { + paramName: `RawTransactions[${index}].RawTransaction`, + txType: 'Batch', + }) + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const rawTx = field.RawTransaction as Record - if (!isObject(rawTx)) { - throw new ValidationError(`Batch: RawTransactions[${index} is not object`) - } + const rawTx = fieldObject.RawTransaction as Record if (rawTx.TransactionType === 'Batch') { throw new ValidationError( - `Batch: RawTransactions[${index} is a Batch transaction. Cannot nest Batch transactions.`, + `Batch: RawTransactions[${index}] is a Batch transaction. Cannot nest Batch transactions.`, ) } }) @@ -125,31 +121,23 @@ export function validateBatch(tx: Record): void { } // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above const fieldObject = field as Record - validateRequiredField( - fieldObject, - 'BatchSigner', - isObject, - `BatchSigners[${index}].BatchSigner`, - ) + validateRequiredField(fieldObject, 'BatchSigner', isObject, { + paramName: `BatchSigners[${index}].BatchSigner`, + txType: 'Batch', + }) // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above const batchSignerObject = fieldObject.BatchSigner as Record - validateRequiredField( - batchSignerObject, - 'Account', - isString, - `BatchSigners[${index}].Account`, - ) - validateOptionalField( - batchSignerObject, - 'SigningPubKey', - isString, - `BatchSigners[${index}].SigningPubKey`, - ) - validateOptionalField( - batchSignerObject, - 'TxnSignature', - isString, - `BatchSigners[${index}].TxnSignature`, - ) + validateRequiredField(batchSignerObject, 'Account', isString, { + paramName: `BatchSigners[${index}].Account`, + txType: 'Batch', + }) + validateOptionalField(batchSignerObject, 'SigningPubKey', isString, { + paramName: `BatchSigners[${index}].SigningPubKey`, + txType: 'Batch', + }) + validateOptionalField(batchSignerObject, 'TxnSignature', isString, { + paramName: `BatchSigners[${index}].TxnSignature`, + txType: 'Batch', + }) }) } diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index e0535ba5dd..80b794b5f9 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -236,7 +236,7 @@ export function isArray(input: unknown): boolean { * @param tx - The object input to check the form and type of. * @param param - The object parameter. * @param checkValidity - The function to use to check the type. - * @param paramName - The name of the object parameter (if different from the parameter). + * @param errorOpts - Extra values to make the error message readable. * @throws */ // eslint-disable-next-line max-params -- helper function @@ -244,19 +244,19 @@ export function validateRequiredField( tx: Record, param: string, checkValidity: (inp: unknown) => boolean, - paramName: string | undefined = undefined, + errorOpts: { + paramName?: string + txType?: string + } = {}, ): void { - const paramNameStr = paramName ?? param + const paramNameStr = errorOpts.paramName ?? param + const txType = errorOpts.txType ?? tx.TransactionType if (tx[param] == null) { - throw new ValidationError( - `${tx.TransactionType}: missing field ${paramNameStr}`, - ) + throw new ValidationError(`${txType}: missing field ${paramNameStr}`) } if (!checkValidity(tx[param])) { - throw new ValidationError( - `${tx.TransactionType}: invalid field ${paramNameStr}`, - ) + throw new ValidationError(`${txType}: invalid field ${paramNameStr}`) } } @@ -266,7 +266,7 @@ export function validateRequiredField( * @param tx - The transaction input to check the form and type of. * @param param - The object parameter. * @param checkValidity - The function to use to check the type. - * @param paramName - The name of the object parameter (if different from the parameter). + * @param errorOpts - Extra values to make the error message readable. * @throws */ // eslint-disable-next-line max-params -- helper function @@ -274,13 +274,15 @@ export function validateOptionalField( tx: Record, param: string, checkValidity: (inp: unknown) => boolean, - paramName: string | undefined = undefined, + errorOpts: { + paramName?: string + txType?: string + } = {}, ): void { - const paramNameStr = paramName ?? param + const paramNameStr = errorOpts.paramName ?? param + const txType = errorOpts.txType ?? tx.TransactionType if (tx[param] !== undefined && !checkValidity(tx[param])) { - throw new ValidationError( - `${tx.TransactionType}: invalid field ${paramNameStr}`, - ) + throw new ValidationError(`${txType}: invalid field ${paramNameStr}`) } } diff --git a/packages/xrpl/test/integration/transactions/batch.test.ts b/packages/xrpl/test/integration/transactions/batch.test.ts index f7c810dd58..191587d986 100644 --- a/packages/xrpl/test/integration/transactions/batch.test.ts +++ b/packages/xrpl/test/integration/transactions/batch.test.ts @@ -7,7 +7,11 @@ import { teardownClient, type XrplIntegrationTestContext, } from '../setup' -import { generateFundedWallet, testTransaction } from '../utils' +import { + generateFundedWallet, + testTransaction, + verifySubmittedTransaction, +} from '../utils' // how long before each test case times out const TIMEOUT = 20000 @@ -17,6 +21,24 @@ describe('Batch', function () { let destination: Wallet let wallet2: Wallet + async function testBatchTransaction( + batch: Batch, + wallet: Wallet, + retry?: { + count: number + delayMs: number + }, + ): Promise { + await testTransaction(testContext.client, batch, wallet, retry) + const promises: Array> = [] + for (const rawTx of batch.RawTransactions) { + promises.push( + verifySubmittedTransaction(testContext.client, rawTx.RawTransaction), + ) + } + await Promise.all(promises) + } + beforeAll(async () => { testContext = await setupClient(serverUrl) wallet2 = await generateFundedWallet(testContext.client) @@ -51,7 +73,7 @@ describe('Batch', function () { ], } const autofilled = await testContext.client.autofill(tx) - await testTransaction(testContext.client, autofilled, testContext.wallet) + await testBatchTransaction(autofilled, testContext.wallet) }, TIMEOUT, ) @@ -85,7 +107,7 @@ describe('Batch', function () { } const autofilled = await testContext.client.autofill(tx) // signMultiBatch(wallet2, autofilled) - await testTransaction(testContext.client, autofilled, testContext.wallet) + await testBatchTransaction(autofilled, testContext.wallet) }, TIMEOUT, ) diff --git a/packages/xrpl/test/models/Batch.test.ts b/packages/xrpl/test/models/Batch.test.ts index d6b3245003..6e742813b1 100644 --- a/packages/xrpl/test/models/Batch.test.ts +++ b/packages/xrpl/test/models/Batch.test.ts @@ -1,7 +1,8 @@ import { assert } from 'chai' -import { validate, ValidationError } from '../../src' +import { validate } from '../../src' import { validateBatch } from '../../src/models/transactions/batch' +import { assertTxValidationError } from '../testUtils' /** * Batch Transaction Verification Testing. @@ -73,45 +74,55 @@ describe('Batch', function () { it('throws w/ invalid BatchSigners', function () { tx.BatchSigners = 0 - - assert.throws( - () => validateBatch(tx), - ValidationError, - 'Batch: invalid field BatchSigners', - ) - assert.throws( - () => validate(tx), - ValidationError, + assertTxValidationError( + tx, + validateBatch, 'Batch: invalid field BatchSigners', ) }) it('throws w/ missing RawTransactions', function () { delete tx.RawTransactions - - assert.throws( - () => validateBatch(tx), - ValidationError, - 'Batch: missing field RawTransactions', - ) - assert.throws( - () => validate(tx), - ValidationError, + assertTxValidationError( + tx, + validateBatch, 'Batch: missing field RawTransactions', ) }) it('throws w/ invalid RawTransactions', function () { tx.RawTransactions = 0 - assert.throws( - () => validateBatch(tx), - ValidationError, + assertTxValidationError( + tx, + validateBatch, 'Batch: invalid field RawTransactions', ) - assert.throws( - () => validate(tx), - ValidationError, - 'Batch: invalid field RawTransactions', + }) + + it('throws w/ invalid RawTransactions object', function () { + tx.RawTransactions = [0] + assertTxValidationError( + tx, + validateBatch, + 'Batch: RawTransactions[0] is not object', + ) + }) + + it('throws w/ invalid RawTransactions.RawTransaction object', function () { + tx.RawTransactions = [{ RawTransaction: 0 }] + assertTxValidationError( + tx, + validateBatch, + 'Batch: invalid field RawTransactions[0].RawTransaction', + ) + }) + + it('throws w/ nested Batch', function () { + tx.RawTransactions = [{ RawTransaction: tx }] + assertTxValidationError( + tx, + validateBatch, + 'Batch: RawTransactions[0] is a Batch transaction. Cannot nest Batch transactions.', ) }) }) diff --git a/packages/xrpl/test/testUtils.ts b/packages/xrpl/test/testUtils.ts index ee922a63e4..71342382de 100644 --- a/packages/xrpl/test/testUtils.ts +++ b/packages/xrpl/test/testUtils.ts @@ -5,7 +5,12 @@ import net from 'net' import { assert } from 'chai' import omit from 'lodash/omit' -import { rippleTimeToUnixTime, unixTimeToRippleTime } from '../src' +import { + rippleTimeToUnixTime, + unixTimeToRippleTime, + validate, + ValidationError, +} from '../src' import addresses from './fixtures/addresses.json' @@ -52,6 +57,22 @@ export function assertResultMatch( ) } +/** + * Check that a transaction error validation fails properly. + * + * @param tx The transaction that should fail validation. + * @param validateTx The transaction-specific validation function (e.g. `validatePayment`). + * @param errorMessage The error message that should be included in the error. + */ +export function assertTxValidationError( + tx: any, + validateTx: (tx: any) => void, + errorMessage: string, +): void { + assert.throws(() => validateTx(tx), ValidationError, errorMessage) + assert.throws(() => validate(tx), ValidationError, errorMessage) +} + /** * Check that the promise rejects with an expected error. * diff --git a/packages/xrpl/test/wallet/batchSigner.test.ts b/packages/xrpl/test/wallet/batchSigner.test.ts index cf86f807eb..1472230909 100644 --- a/packages/xrpl/test/wallet/batchSigner.test.ts +++ b/packages/xrpl/test/wallet/batchSigner.test.ts @@ -9,6 +9,7 @@ import { Wallet, } from '../../src' import { + BatchFlags, BatchInnerTransaction, BatchSigner, } from '../../src/models/transactions/batch' @@ -28,6 +29,13 @@ const submitWallet = Wallet.fromSeed('sEd7HmQFsoyj5TAm6d98gytM9LJA1MF', { }) const otherWallet = Wallet.generate() +const nonBatchTx = { + TransactionType: 'Payment', + Account: 'rJy554HmWFFJQGnRfZuoo8nV97XSMq77h7', + Destination: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Amount: '1000', +} + interface RawTransaction { RawTransaction: BatchInnerTransaction } @@ -116,6 +124,15 @@ describe('Wallet batch operations', function () { 'Must be signing for an address included in the Batch.', ) }) + + it('fails with non-Batch transaction', function () { + assert.throws( + // @ts-expect-error - needed for JS/codecov + () => signMultiBatch(otherWallet, nonBatchTx), + ValidationError, + 'Must be a Batch transaction.', + ) + }) }) describe('combineBatchSigners', function () { @@ -123,14 +140,13 @@ describe('Wallet batch operations', function () { let tx2: Batch const originalTx: Batch = { Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', - Flags: 1, + Flags: BatchFlags.tfAllOrNothing, LastLedgerSequence: 14973, NetworkID: 21336, RawTransactions: [ { RawTransaction: { Account: 'rJy554HmWFFJQGnRfZuoo8nV97XSMq77h7', - Flags: 0x40000000, Amount: '5000000', Destination: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', Fee: '0', @@ -142,7 +158,6 @@ describe('Wallet batch operations', function () { { RawTransaction: { Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', - Flags: 0x40000000, Amount: '1000000', Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', Fee: '0', @@ -213,5 +228,58 @@ describe('Wallet batch operations', function () { const expected = (tx1.BatchSigners ?? []).concat(tx2.BatchSigners ?? []) assert.deepEqual(decode(result).BatchSigners, expected) }) + + it('fails with no transactions provided', function () { + assert.throws( + () => combineBatchSigners([]), + ValidationError, + 'There are 0 transactions to combine.', + ) + }) + + it('fails with non-Batch transaction provided', function () { + assert.throws( + // @ts-expect-error - needed for JS/codecov + () => combineBatchSigners([tx1, tx2, nonBatchTx]), + ValidationError, + 'TransactionType must be `Batch`.', + ) + }) + + it('fails with no BatchSigners provided in a transaction', function () { + const badTx1 = { ...tx1 } + delete badTx1.BatchSigners + assert.throws( + () => combineBatchSigners([badTx1, tx2]), + ValidationError, + 'For combining Batch transaction signatures, all transactions must include a BatchSigners field containing an array of signatures.', + ) + + badTx1.BatchSigners = [] + assert.throws( + () => combineBatchSigners([badTx1, tx2]), + ValidationError, + 'For combining Batch transaction signatures, all transactions must include a BatchSigners field containing an array of signatures.', + ) + }) + + it('fails with signed inner transaction', function () { + assert.throws( + () => combineBatchSigners([secpWallet.sign(tx1).tx_blob, tx2]), + ValidationError, + 'Batch transaction must be unsigned.', + ) + }) + + it('fails with different inner transactions', function () { + const badTx2 = { ...tx2 } + badTx2.Flags = BatchFlags.tfIndependent + signMultiBatch(secpWallet, tx2) + assert.throws( + () => combineBatchSigners([tx1, badTx2]), + ValidationError, + 'Flags and transaction hashes are not the same for all provided transactions.', + ) + }) }) }) From a5d72f9ee4fd8ade65d5644bf45c68bef56990f9 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Sat, 11 Jan 2025 19:19:35 -0500 Subject: [PATCH 41/73] remove LedgerStateFix --- .../xrpl/src/models/transactions/index.ts | 1 - .../src/models/transactions/ledgerStateFix.ts | 33 --------- .../src/models/transactions/transaction.ts | 6 -- .../xrpl/test/models/LedgerStateFix.test.ts | 72 ------------------- 4 files changed, 112 deletions(-) delete mode 100644 packages/xrpl/src/models/transactions/ledgerStateFix.ts delete mode 100644 packages/xrpl/test/models/LedgerStateFix.test.ts diff --git a/packages/xrpl/src/models/transactions/index.ts b/packages/xrpl/src/models/transactions/index.ts index 2c7856a3f0..dd2c71b13d 100644 --- a/packages/xrpl/src/models/transactions/index.ts +++ b/packages/xrpl/src/models/transactions/index.ts @@ -106,4 +106,3 @@ export { XChainModifyBridgeFlagsInterface, } from './XChainModifyBridge' export { Batch } from './batch' -export { LedgerStateFix } from './ledgerStateFix' diff --git a/packages/xrpl/src/models/transactions/ledgerStateFix.ts b/packages/xrpl/src/models/transactions/ledgerStateFix.ts deleted file mode 100644 index 4ef7fd7f98..0000000000 --- a/packages/xrpl/src/models/transactions/ledgerStateFix.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - BaseTransaction, - isNumber, - isString, - validateBaseTransaction, - validateOptionalField, - validateRequiredField, -} from './common' - -/** - * @category Transaction Models - */ -export interface LedgerStateFix extends BaseTransaction { - TransactionType: 'LedgerStateFix' - - LedgerFixType: number - - Owner?: string -} - -/** - * Verify the form and type of a LedgerStateFix at runtime. - * - * @param tx - A LedgerStateFix Transaction. - * @throws When the LedgerStateFix is malformed. - */ -export function validateLedgerStateFix(tx: Record): void { - validateBaseTransaction(tx) - - validateRequiredField(tx, 'LedgerFixType', isNumber) - - validateOptionalField(tx, 'Owner', isString) -} diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index 40a533fa02..1d947fde40 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -30,7 +30,6 @@ import { EnableAmendment } from './enableAmendment' import { EscrowCancel, validateEscrowCancel } from './escrowCancel' import { EscrowCreate, validateEscrowCreate } from './escrowCreate' import { EscrowFinish, validateEscrowFinish } from './escrowFinish' -import { LedgerStateFix, validateLedgerStateFix } from './ledgerStateFix' import { TransactionMetadata } from './metadata' import { MPTokenAuthorize, validateMPTokenAuthorize } from './MPTokenAuthorize' import { @@ -137,7 +136,6 @@ export type SubmittableTransaction = | EscrowCancel | EscrowCreate | EscrowFinish - | LedgerStateFix | MPTokenAuthorize | MPTokenIssuanceCreate | MPTokenIssuanceDestroy @@ -358,10 +356,6 @@ export function validate(transaction: Record): void { validateEscrowFinish(tx) break - case 'LedgerStateFix': - validateLedgerStateFix(tx) - break - case 'MPTokenAuthorize': validateMPTokenAuthorize(tx) break diff --git a/packages/xrpl/test/models/LedgerStateFix.test.ts b/packages/xrpl/test/models/LedgerStateFix.test.ts deleted file mode 100644 index c890c9f395..0000000000 --- a/packages/xrpl/test/models/LedgerStateFix.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { assert } from 'chai' - -import { validate, ValidationError } from '../../src' -import { validateLedgerStateFix } from '../../src/models/transactions/ledgerStateFix' - -/** - * LedgerStateFix Transaction Verification Testing. - * - * Providing runtime verification testing for each specific transaction type. - */ -describe('LedgerStateFix', function () { - let tx - - beforeEach(function () { - tx = { - Account: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', - TransactionType: 'LedgerStateFix', - LedgerFixType: 1, - Owner: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', - } as any - }) - - it('verifies valid LedgerStateFix', function () { - assert.doesNotThrow(() => validateLedgerStateFix(tx)) - assert.doesNotThrow(() => validate(tx)) - }) - - it('throws w/ missing LedgerFixType', function () { - delete tx.LedgerFixType - - assert.throws( - () => validateLedgerStateFix(tx), - ValidationError, - 'LedgerStateFix: missing field LedgerFixType', - ) - assert.throws( - () => validate(tx), - ValidationError, - 'LedgerStateFix: missing field LedgerFixType', - ) - }) - - it('throws w/ invalid LedgerFixType', function () { - tx.LedgerFixType = 'number' - - assert.throws( - () => validateLedgerStateFix(tx), - ValidationError, - 'LedgerStateFix: invalid field LedgerFixType', - ) - assert.throws( - () => validate(tx), - ValidationError, - 'LedgerStateFix: invalid field LedgerFixType', - ) - }) - - it('throws w/ invalid Owner', function () { - tx.Owner = 123 - - assert.throws( - () => validateLedgerStateFix(tx), - ValidationError, - 'LedgerStateFix: invalid field Owner', - ) - assert.throws( - () => validate(tx), - ValidationError, - 'LedgerStateFix: invalid field Owner', - ) - }) -}) From 08543fc1d48f1837fddb4b6816a4276efb75f13e Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Sat, 11 Jan 2025 19:21:34 -0500 Subject: [PATCH 42/73] fix build issues --- packages/xrpl/src/models/transactions/common.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index 80b794b5f9..8af598938b 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -236,7 +236,9 @@ export function isArray(input: unknown): boolean { * @param tx - The object input to check the form and type of. * @param param - The object parameter. * @param checkValidity - The function to use to check the type. - * @param errorOpts - Extra values to make the error message readable. + * @param errorOpts - Extra values to make the error message easier to understand. + * @param txType - The transaction type throwing the error. + * @param errorOpts.paramName - The name of the parameter in the transaction with the error. * @throws */ // eslint-disable-next-line max-params -- helper function @@ -245,8 +247,8 @@ export function validateRequiredField( param: string, checkValidity: (inp: unknown) => boolean, errorOpts: { - paramName?: string txType?: string + paramName?: string } = {}, ): void { const paramNameStr = errorOpts.paramName ?? param @@ -266,7 +268,9 @@ export function validateRequiredField( * @param tx - The transaction input to check the form and type of. * @param param - The object parameter. * @param checkValidity - The function to use to check the type. - * @param errorOpts - Extra values to make the error message readable. + * @param errorOpts - Extra values to make the error message easier to understand. + * @param txType - The transaction type throwing the error. + * @param errorOpts.paramName - The name of the parameter in the transaction with the error. * @throws */ // eslint-disable-next-line max-params -- helper function @@ -275,8 +279,8 @@ export function validateOptionalField( param: string, checkValidity: (inp: unknown) => boolean, errorOpts: { - paramName?: string txType?: string + paramName?: string } = {}, ): void { const paramNameStr = errorOpts.paramName ?? param From d243ecccb6efafd118cdd373d920df0c49c32d55 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Sat, 11 Jan 2025 19:28:31 -0500 Subject: [PATCH 43/73] uncomment now-passing test --- packages/xrpl/test/integration/transactions/batch.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/xrpl/test/integration/transactions/batch.test.ts b/packages/xrpl/test/integration/transactions/batch.test.ts index 191587d986..e5318fbc8e 100644 --- a/packages/xrpl/test/integration/transactions/batch.test.ts +++ b/packages/xrpl/test/integration/transactions/batch.test.ts @@ -1,6 +1,6 @@ import { Batch, Wallet } from '../../../src' import { BatchFlags } from '../../../src/models/transactions/batch' -// import { signMultiBatch } from '../../../src/Wallet/batchSigner' +import { signMultiBatch } from '../../../src/Wallet/batchSigner' import serverUrl from '../serverUrl' import { setupClient, @@ -106,7 +106,7 @@ describe('Batch', function () { ], } const autofilled = await testContext.client.autofill(tx) - // signMultiBatch(wallet2, autofilled) + signMultiBatch(wallet2, autofilled) await testBatchTransaction(autofilled, testContext.wallet) }, TIMEOUT, From 503cf6c803add16310bec70126ce21884369fd4b Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Sat, 11 Jan 2025 19:46:14 -0500 Subject: [PATCH 44/73] fix linter --- packages/xrpl/src/models/transactions/common.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index 8af598938b..a2bcf6a858 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -237,7 +237,7 @@ export function isArray(input: unknown): boolean { * @param param - The object parameter. * @param checkValidity - The function to use to check the type. * @param errorOpts - Extra values to make the error message easier to understand. - * @param txType - The transaction type throwing the error. + * @param errorOpts.txType - The transaction type throwing the error. * @param errorOpts.paramName - The name of the parameter in the transaction with the error. * @throws */ @@ -269,7 +269,7 @@ export function validateRequiredField( * @param param - The object parameter. * @param checkValidity - The function to use to check the type. * @param errorOpts - Extra values to make the error message easier to understand. - * @param txType - The transaction type throwing the error. + * @param errorOpts.txType - The transaction type throwing the error. * @param errorOpts.paramName - The name of the parameter in the transaction with the error. * @throws */ From b3b2c4cad34992c7229f73e68974f629c8f321ae Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Sat, 11 Jan 2025 23:32:16 -0500 Subject: [PATCH 45/73] drive-by multisign fix --- packages/xrpl/src/Wallet/index.ts | 2 +- packages/xrpl/test/wallet/index.test.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index e5f801bceb..4569c1d520 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -383,7 +383,7 @@ export class Wallet { hash: string } { let multisignAddress: boolean | string = false - if (typeof multisign === 'string' && multisign.startsWith('X')) { + if (typeof multisign === 'string') { multisignAddress = multisign } else if (multisign) { multisignAddress = this.classicAddress diff --git a/packages/xrpl/test/wallet/index.test.ts b/packages/xrpl/test/wallet/index.test.ts index bbb454108f..5647c8df93 100644 --- a/packages/xrpl/test/wallet/index.test.ts +++ b/packages/xrpl/test/wallet/index.test.ts @@ -598,6 +598,17 @@ describe('Wallet', function () { }) }) + it('sign with regular address for multisignAddress', async function () { + const signature = wallet.sign( + REQUEST_FIXTURES.signAs as Transaction, + wallet.address, + ) + assert.deepEqual(signature, { + tx_blob: RESPONSE_FIXTURES.signAs.signedTransaction, + hash: 'D8CF5FC93CFE5E131A34599AFB7CE186A5B8D1B9F069E35F4634AD3B27837E35', + }) + }) + it('sign with X Address and tag for multisignAddress', async function () { const signature = wallet.sign( REQUEST_FIXTURES.signAs as Transaction, From b092a94e876efe76cc7817805c9956cf7e257f3b Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Sat, 11 Jan 2025 23:52:17 -0500 Subject: [PATCH 46/73] add more tests --- packages/xrpl/src/Wallet/batchSigner.ts | 44 +++++----- .../xrpl/src/models/transactions/batch.ts | 34 ++++---- packages/xrpl/test/models/Batch.test.ts | 55 +++++++++--- packages/xrpl/test/wallet/batchSigner.test.ts | 85 +++++++++++++++++++ 4 files changed, 173 insertions(+), 45 deletions(-) diff --git a/packages/xrpl/src/Wallet/batchSigner.ts b/packages/xrpl/src/Wallet/batchSigner.ts index 12b6df40f4..aa30b5deda 100644 --- a/packages/xrpl/src/Wallet/batchSigner.ts +++ b/packages/xrpl/src/Wallet/batchSigner.ts @@ -5,7 +5,7 @@ import { decode, encode, encodeForSigningBatch } from 'ripple-binary-codec' import { sign } from 'ripple-keypairs' import { ValidationError } from '../errors' -import { Batch, Signer, Transaction, validate } from '../models' +import { Batch, Transaction, validate } from '../models' import { BatchSigner, validateBatch } from '../models/transactions/batch' import { hashSignedTx } from '../utils/hashes' @@ -16,19 +16,22 @@ import { Wallet } from '.' * * @param wallet - Wallet instance. * @param transaction - The Batch transaction to sign. - * @param multisign - Specify true/false to use multisign or actual address (classic/x-address) to make multisign tx request. + * @param opts - Additional options for regular key and multi-signing complexity. + * @param opts.batchAccount - The account submitting the inner Batch transaction, on behalf of which is this signature. + * @param opts.multisign - Specify true/false to use multisign or actual address (classic/x-address) to make multisign tx request. * @throws ValidationError if the transaction is malformed. */ // eslint-disable-next-line max-lines-per-function -- TODO: refactor export function signMultiBatch( wallet: Wallet, transaction: Batch, - multisign?: boolean | string, + opts: { batchAccount?: string; multisign?: boolean | string } = {}, ): void { + const batchAccount = opts.batchAccount ?? wallet.classicAddress let multisignAddress: boolean | string = false - if (typeof multisign === 'string' && multisign.startsWith('X')) { - multisignAddress = multisign - } else if (multisign) { + if (typeof opts.multisign === 'string') { + multisignAddress = opts.multisign + } else if (opts.multisign) { multisignAddress = wallet.classicAddress } @@ -40,7 +43,7 @@ export function signMultiBatch( const involvedAccounts = transaction.RawTransactions.map( (raw) => raw.RawTransaction.Account, ) - if (!involvedAccounts.includes(multisignAddress || wallet.address)) { + if (!involvedAccounts.includes(batchAccount)) { throw new ValidationError( 'Must be signing for an address included in the Batch.', ) @@ -58,26 +61,27 @@ export function signMultiBatch( } let batchSigner: BatchSigner if (multisignAddress) { - const signer: Signer = { - Signer: { - Account: multisignAddress, - SigningPubKey: wallet.publicKey, - TxnSignature: sign( - encodeForSigningBatch(fieldsToSign), - wallet.privateKey, - ), - }, - } batchSigner = { BatchSigner: { - Account: multisignAddress, - Signers: [signer], + Account: batchAccount, + Signers: [ + { + Signer: { + Account: multisignAddress, + SigningPubKey: wallet.publicKey, + TxnSignature: sign( + encodeForSigningBatch(fieldsToSign), + wallet.privateKey, + ), + }, + }, + ], }, } } else { batchSigner = { BatchSigner: { - Account: wallet.address, + Account: batchAccount, SigningPubKey: wallet.publicKey, TxnSignature: sign( encodeForSigningBatch(fieldsToSign), diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index 1e589b3ddc..6448e5a0e8 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -88,21 +88,21 @@ export function validateBatch(tx: Record): void { validateRequiredField(tx, 'RawTransactions', isArray) // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above const rawTransactions = tx.RawTransactions as unknown[] - rawTransactions.forEach((field, index) => { - if (!isObject(field)) { + rawTransactions.forEach((rawTxObj, index) => { + if (!isObject(rawTxObj)) { throw new ValidationError( - `Batch: RawTransactions[${index}] is not object`, + `Batch: RawTransactions[${index}] is not object.`, ) } // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const fieldObject = field as Record - validateRequiredField(fieldObject, 'RawTransaction', isObject, { + const rawTxRecord = rawTxObj as Record + validateRequiredField(rawTxRecord, 'RawTransaction', isObject, { paramName: `RawTransactions[${index}].RawTransaction`, txType: 'Batch', }) // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const rawTx = fieldObject.RawTransaction as Record + const rawTx = rawTxRecord.RawTransaction as Record if (rawTx.TransactionType === 'Batch') { throw new ValidationError( `Batch: RawTransactions[${index}] is a Batch transaction. Cannot nest Batch transactions.`, @@ -115,29 +115,33 @@ export function validateBatch(tx: Record): void { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above const batchSigners = tx.BatchSigners as unknown[] | undefined - batchSigners?.forEach((field, index) => { - if (!isObject(field)) { - throw new ValidationError(`Batch: BatchSigners[${index} is not object`) + batchSigners?.forEach((signerObj, index) => { + if (!isObject(signerObj)) { + throw new ValidationError(`Batch: BatchSigners[${index}] is not object.`) } // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const fieldObject = field as Record - validateRequiredField(fieldObject, 'BatchSigner', isObject, { + const signerRecord = signerObj as Record + validateRequiredField(signerRecord, 'BatchSigner', isObject, { paramName: `BatchSigners[${index}].BatchSigner`, txType: 'Batch', }) // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const batchSignerObject = fieldObject.BatchSigner as Record - validateRequiredField(batchSignerObject, 'Account', isString, { + const signer = signerRecord.BatchSigner as Record + validateRequiredField(signer, 'Account', isString, { paramName: `BatchSigners[${index}].Account`, txType: 'Batch', }) - validateOptionalField(batchSignerObject, 'SigningPubKey', isString, { + validateOptionalField(signer, 'SigningPubKey', isString, { paramName: `BatchSigners[${index}].SigningPubKey`, txType: 'Batch', }) - validateOptionalField(batchSignerObject, 'TxnSignature', isString, { + validateOptionalField(signer, 'TxnSignature', isString, { paramName: `BatchSigners[${index}].TxnSignature`, txType: 'Batch', }) + validateOptionalField(signer, 'Signers', isArray, { + paramName: `BatchSigners[${index}].Signers`, + txType: 'Batch', + }) }) } diff --git a/packages/xrpl/test/models/Batch.test.ts b/packages/xrpl/test/models/Batch.test.ts index 6e742813b1..e2e8618985 100644 --- a/packages/xrpl/test/models/Batch.test.ts +++ b/packages/xrpl/test/models/Batch.test.ts @@ -32,11 +32,6 @@ describe('Batch', function () { RawTransaction: { Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', Amount: '5000000', - BatchTxn: { - BatchIndex: 1, - OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', - Sequence: 215, - }, Destination: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', Fee: '0', NetworkID: 21336, @@ -49,11 +44,6 @@ describe('Batch', function () { RawTransaction: { Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', Amount: '1000000', - BatchTxn: { - BatchIndex: 0, - OuterAccount: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', - Sequence: 470, - }, Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', Fee: '0', NetworkID: 21336, @@ -72,6 +62,42 @@ describe('Batch', function () { assert.doesNotThrow(() => validate(tx)) }) + it('verifies single-account Batch', function () { + tx = { + Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Flags: 1, + RawTransactions: [ + { + RawTransaction: { + Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Amount: '5000000', + Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Fee: '0', + NetworkID: 21336, + Sequence: 0, + SigningPubKey: '', + TransactionType: 'Payment', + }, + }, + { + RawTransaction: { + Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK', + Amount: '1000000', + Destination: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + Fee: '0', + NetworkID: 21336, + Sequence: 0, + SigningPubKey: '', + TransactionType: 'Payment', + }, + }, + ], + TransactionType: 'Batch', + } + assert.doesNotThrow(() => validateBatch(tx)) + assert.doesNotThrow(() => validate(tx)) + }) + it('throws w/ invalid BatchSigners', function () { tx.BatchSigners = 0 assertTxValidationError( @@ -125,4 +151,13 @@ describe('Batch', function () { 'Batch: RawTransactions[0] is a Batch transaction. Cannot nest Batch transactions.', ) }) + + it('throws w/ non-object in BatchSigner list', function () { + tx.BatchSigners = [1] + assertTxValidationError( + tx, + validateBatch, + 'Batch: BatchSigners[0] is not object.', + ) + }) }) diff --git a/packages/xrpl/test/wallet/batchSigner.test.ts b/packages/xrpl/test/wallet/batchSigner.test.ts index 1472230909..b431fada9f 100644 --- a/packages/xrpl/test/wallet/batchSigner.test.ts +++ b/packages/xrpl/test/wallet/batchSigner.test.ts @@ -27,6 +27,9 @@ const edWallet = Wallet.fromSeed('spkcsko6Ag3RbCSVXV2FJ8Pd4Zac1', { const submitWallet = Wallet.fromSeed('sEd7HmQFsoyj5TAm6d98gytM9LJA1MF', { algorithm: ECDSA.ed25519, }) +const regkeyWallet = Wallet.fromSeed('sEdStM1pngFcLQqVfH3RQcg2Qr6ov9e', { + algorithm: ECDSA.ed25519, +}) const otherWallet = Wallet.generate() const nonBatchTx = { @@ -117,6 +120,88 @@ describe('Wallet batch operations', function () { ) }) + it('succeeds with a different account', function () { + signMultiBatch(regkeyWallet, transaction, { + batchAccount: edWallet.address, + }) + const expected = [ + { + BatchSigner: { + Account: 'rJy554HmWFFJQGnRfZuoo8nV97XSMq77h7', + SigningPubKey: + 'ED37D3F048B7F1E680B0A97F70C7843160B9F25D6398D07E68B9A2C83AA8E1B156', + TxnSignature: + 'E53E2821CE46C98638E46CA0E6DB712CE45CEC45A697830A5028873D2BA51E1FA008F20526AC16B609401E2F1F8938AE60603223BC9D82A0221CFA5E58C90807', + }, + }, + ] + assert.property(transaction, 'BatchSigners') + assert.strictEqual( + JSON.stringify(transaction.BatchSigners), + JSON.stringify(expected), + ) + }) + + it('succeeds with multisign', function () { + signMultiBatch(regkeyWallet, transaction, { + batchAccount: edWallet.address, + multisign: true, + }) + const expected = [ + { + BatchSigner: { + Account: 'rJy554HmWFFJQGnRfZuoo8nV97XSMq77h7', + Signers: [ + { + Signer: { + Account: 'rwRNeznwHzdfYeKWpevYmax2NSDioyeEtT', + SigningPubKey: + 'ED37D3F048B7F1E680B0A97F70C7843160B9F25D6398D07E68B9A2C83AA8E1B156', + TxnSignature: + 'E53E2821CE46C98638E46CA0E6DB712CE45CEC45A697830A5028873D2BA51E1FA008F20526AC16B609401E2F1F8938AE60603223BC9D82A0221CFA5E58C90807', + }, + }, + ], + }, + }, + ] + assert.property(transaction, 'BatchSigners') + assert.strictEqual( + JSON.stringify(transaction.BatchSigners), + JSON.stringify(expected), + ) + }) + + it('succeeds with multisign + regular key', function () { + signMultiBatch(regkeyWallet, transaction, { + batchAccount: edWallet.address, + multisign: submitWallet.address, + }) + const expected = [ + { + BatchSigner: { + Account: 'rJy554HmWFFJQGnRfZuoo8nV97XSMq77h7', + Signers: [ + { + Signer: { + Account: 'rJCxK2hX9tDMzbnn3cg1GU2g19Kfmhzxkp', + SigningPubKey: + 'ED37D3F048B7F1E680B0A97F70C7843160B9F25D6398D07E68B9A2C83AA8E1B156', + TxnSignature: + 'E53E2821CE46C98638E46CA0E6DB712CE45CEC45A697830A5028873D2BA51E1FA008F20526AC16B609401E2F1F8938AE60603223BC9D82A0221CFA5E58C90807', + }, + }, + ], + }, + }, + ] + assert.property(transaction, 'BatchSigners') + assert.strictEqual( + JSON.stringify(transaction.BatchSigners), + JSON.stringify(expected), + ) + }) + it('fails with not-included account', function () { assert.throws( () => signMultiBatch(otherWallet, transaction), From c48957d1169773e3227ae5cb7bde58aa732db908 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Mon, 13 Jan 2025 14:56:56 -0500 Subject: [PATCH 47/73] better docstrings --- packages/xrpl/src/Wallet/batchSigner.ts | 1 + packages/xrpl/src/Wallet/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/xrpl/src/Wallet/batchSigner.ts b/packages/xrpl/src/Wallet/batchSigner.ts index aa30b5deda..e4fe4f5b7d 100644 --- a/packages/xrpl/src/Wallet/batchSigner.ts +++ b/packages/xrpl/src/Wallet/batchSigner.ts @@ -19,6 +19,7 @@ import { Wallet } from '.' * @param opts - Additional options for regular key and multi-signing complexity. * @param opts.batchAccount - The account submitting the inner Batch transaction, on behalf of which is this signature. * @param opts.multisign - Specify true/false to use multisign or actual address (classic/x-address) to make multisign tx request. + * The actual address is only needed in the case of regular key usage. * @throws ValidationError if the transaction is malformed. */ // eslint-disable-next-line max-lines-per-function -- TODO: refactor diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index 4569c1d520..db1f4a313b 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -369,6 +369,7 @@ export class Wallet { * @param this - Wallet instance. * @param transaction - A transaction to be signed offline. * @param multisign - Specify true/false to use multisign or actual address (classic/x-address) to make multisign tx request. + * The actual address is only needed in the case of regular key usage. * @returns A signed transaction. * @throws ValidationError if the transaction is already signed or does not encode/decode to same result. * @throws XrplError if the issued currency being signed is XRP ignoring case. From 793d42f2bac049f76a863df59a1e2920d747ccd8 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 5 Feb 2025 17:45:09 -0800 Subject: [PATCH 48/73] redo definitions.json --- .../src/enums/definitions.json | 2462 ++++++++--------- 1 file changed, 1230 insertions(+), 1232 deletions(-) diff --git a/packages/ripple-binary-codec/src/enums/definitions.json b/packages/ripple-binary-codec/src/enums/definitions.json index bb10e02004..e06ebcf3ce 100644 --- a/packages/ripple-binary-codec/src/enums/definitions.json +++ b/packages/ripple-binary-codec/src/enums/definitions.json @@ -1,3237 +1,3235 @@ { - "TYPES": { - "Done": -1, - "Unknown": -2, - "NotPresent": 0, - "UInt16": 1, - "UInt32": 2, - "UInt64": 3, - "Hash128": 4, - "Hash256": 5, - "Amount": 6, - "Blob": 7, - "AccountID": 8, - "Number": 9, - "STObject": 14, - "STArray": 15, - "UInt8": 16, - "Hash160": 17, - "PathSet": 18, - "Vector256": 19, - "UInt96": 20, - "Hash192": 21, - "UInt384": 22, - "UInt512": 23, - "Issue": 24, - "XChainBridge": 25, - "Currency": 26, - "Transaction": 10001, - "LedgerEntry": 10002, - "Validation": 10003, - "Metadata": 10004 - }, - "LEDGER_ENTRY_TYPES": { - "Any": -3, - "Child": -2, - "Invalid": -1, - "NFTokenOffer": 55, - "Check": 67, - "DID": 73, - "NegativeUNL": 78, - "NFTokenPage": 80, - "SignerList": 83, - "Ticket": 84, - "AccountRoot": 97, - "DirectoryNode": 100, - "Amendments": 102, - "LedgerHashes": 104, - "Bridge": 105, - "Offer": 111, - "DepositPreauth": 112, - "XChainOwnedClaimID": 113, - "RippleState": 114, - "FeeSettings": 115, - "XChainOwnedCreateAccountClaimID": 116, - "Escrow": 117, - "PayChannel": 120, - "AMM": 121, - "Oracle": 128, - "MPTokenIssuance": 126, - "MPToken": 127, - "Credential": 129, - "PermissionedDomain": 130 - }, "FIELDS": [ [ "Generic", { - "nth": 0, - "isVLEncoded": false, "isSerialized": false, "isSigningField": false, + "isVLEncoded": false, + "nth": 0, "type": "Unknown" } ], [ "Invalid", { - "nth": -1, - "isVLEncoded": false, "isSerialized": false, "isSigningField": false, + "isVLEncoded": false, + "nth": -1, "type": "Unknown" } ], [ "ObjectEndMarker", { - "nth": 1, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 1, "type": "STObject" } ], [ "ArrayEndMarker", { - "nth": 1, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 1, "type": "STArray" } ], [ - "hash", + "taker_gets_funded", { - "nth": 257, - "isVLEncoded": false, "isSerialized": false, "isSigningField": false, - "type": "Hash256" - } - ], - [ - "index", - { - "nth": 258, "isVLEncoded": false, - "isSerialized": false, - "isSigningField": false, - "type": "Hash256" - } - ], - [ - "taker_gets_funded", - { "nth": 258, - "isVLEncoded": false, - "isSerialized": false, - "isSigningField": false, "type": "Amount" } ], [ "taker_pays_funded", { - "nth": 259, - "isVLEncoded": false, "isSerialized": false, "isSigningField": false, + "isVLEncoded": false, + "nth": 259, "type": "Amount" } ], [ - "LedgerEntry", + "LedgerEntryType", { - "nth": 257, + "isSerialized": true, + "isSigningField": true, "isVLEncoded": false, - "isSerialized": false, - "isSigningField": false, - "type": "LedgerEntry" + "nth": 1, + "type": "UInt16" } ], [ - "Transaction", + "TransactionType", { - "nth": 257, + "isSerialized": true, + "isSigningField": true, "isVLEncoded": false, - "isSerialized": false, - "isSigningField": false, - "type": "Transaction" + "nth": 2, + "type": "UInt16" } ], [ - "Validation", + "SignerWeight", { - "nth": 257, + "isSerialized": true, + "isSigningField": true, "isVLEncoded": false, - "isSerialized": false, - "isSigningField": false, - "type": "Validation" + "nth": 3, + "type": "UInt16" } ], [ - "Metadata", + "TransferFee", { - "nth": 257, + "isSerialized": true, + "isSigningField": true, "isVLEncoded": false, - "isSerialized": false, - "isSigningField": false, - "type": "Metadata" + "nth": 4, + "type": "UInt16" } ], [ - "CloseResolution", + "TradingFee", { - "nth": 1, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt8" + "isVLEncoded": false, + "nth": 5, + "type": "UInt16" } ], [ - "Method", + "DiscountedFee", { - "nth": 2, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt8" + "isVLEncoded": false, + "nth": 6, + "type": "UInt16" } ], [ - "TransactionResult", + "Version", { - "nth": 3, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt8" + "isVLEncoded": false, + "nth": 16, + "type": "UInt16" } ], [ - "Scale", + "HookStateChangeCount", { - "nth": 4, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt8" + "isVLEncoded": false, + "nth": 17, + "type": "UInt16" } ], [ - "AssetScale", + "HookEmitCount", { - "nth": 5, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt8" + "isVLEncoded": false, + "nth": 18, + "type": "UInt16" } ], [ - "TickSize", + "HookExecutionIndex", { - "nth": 16, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt8" + "isVLEncoded": false, + "nth": 19, + "type": "UInt16" } ], [ - "UNLModifyDisabling", + "HookApiVersion", { - "nth": 17, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt8" + "isVLEncoded": false, + "nth": 20, + "type": "UInt16" } ], [ - "HookResult", + "LedgerFixType", { - "nth": 18, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt8" + "isVLEncoded": false, + "nth": 21, + "type": "UInt16" } ], [ - "WasLockingChainSend", + "NetworkID", { - "nth": 19, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt8" + "isVLEncoded": false, + "nth": 1, + "type": "UInt32" } ], [ - "LedgerEntryType", + "Flags", { - "nth": 1, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 2, + "type": "UInt32" } ], [ - "TransactionType", + "SourceTag", { - "nth": 2, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 3, + "type": "UInt32" } ], [ - "SignerWeight", + "Sequence", { - "nth": 3, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 4, + "type": "UInt32" } ], [ - "TransferFee", + "PreviousTxnLgrSeq", { - "nth": 4, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 5, + "type": "UInt32" } ], [ - "TradingFee", + "LedgerSequence", { - "nth": 5, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 6, + "type": "UInt32" } ], [ - "DiscountedFee", + "CloseTime", { - "nth": 6, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" - } + "isVLEncoded": false, + "nth": 7, + "type": "UInt32" + } ], [ - "Version", + "ParentCloseTime", { - "nth": 16, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 8, + "type": "UInt32" } ], [ - "HookStateChangeCount", + "SigningTime", { - "nth": 17, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 9, + "type": "UInt32" } ], [ - "HookEmitCount", + "Expiration", { - "nth": 18, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 10, + "type": "UInt32" } ], [ - "HookExecutionIndex", + "TransferRate", { - "nth": 19, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 11, + "type": "UInt32" } ], [ - "HookApiVersion", + "WalletSize", { - "nth": 20, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 12, + "type": "UInt32" } ], [ - "LedgerFixType", + "OwnerCount", { - "nth": 21, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt16" + "isVLEncoded": false, + "nth": 13, + "type": "UInt32" } ], [ - "NetworkID", + "DestinationTag", { - "nth": 1, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 14, "type": "UInt32" } ], [ - "Flags", + "LastUpdateTime", { - "nth": 2, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 15, "type": "UInt32" } ], [ - "SourceTag", + "HighQualityIn", { - "nth": 3, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 16, "type": "UInt32" } ], [ - "Sequence", + "HighQualityOut", { - "nth": 4, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 17, "type": "UInt32" } ], [ - "PreviousTxnLgrSeq", + "LowQualityIn", { - "nth": 5, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 18, "type": "UInt32" } ], [ - "LedgerSequence", + "LowQualityOut", { - "nth": 6, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 19, "type": "UInt32" } ], [ - "CloseTime", + "QualityIn", { - "nth": 7, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 20, "type": "UInt32" } ], [ - "ParentCloseTime", + "QualityOut", { - "nth": 8, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 21, "type": "UInt32" } ], [ - "SigningTime", + "StampEscrow", { - "nth": 9, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 22, "type": "UInt32" } ], [ - "Expiration", + "BondAmount", { - "nth": 10, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 23, "type": "UInt32" } ], [ - "TransferRate", + "LoadFee", { - "nth": 11, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 24, "type": "UInt32" } ], [ - "WalletSize", + "OfferSequence", { - "nth": 12, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 25, "type": "UInt32" } ], [ - "OwnerCount", + "FirstLedgerSequence", { - "nth": 13, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 26, "type": "UInt32" } ], [ - "DestinationTag", + "LastLedgerSequence", { - "nth": 14, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 27, "type": "UInt32" } ], [ - "LastUpdateTime", + "TransactionIndex", { - "nth": 15, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 28, "type": "UInt32" } ], [ - "HighQualityIn", + "OperationLimit", { - "nth": 16, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 29, "type": "UInt32" } ], [ - "HighQualityOut", + "ReferenceFeeUnits", { - "nth": 17, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 30, "type": "UInt32" } ], [ - "LowQualityIn", + "ReserveBase", { - "nth": 18, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 31, "type": "UInt32" } ], [ - "LowQualityOut", + "ReserveIncrement", { - "nth": 19, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 32, "type": "UInt32" } ], [ - "QualityIn", + "SetFlag", { - "nth": 20, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 33, "type": "UInt32" } ], [ - "QualityOut", + "ClearFlag", { - "nth": 21, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 34, "type": "UInt32" } ], [ - "StampEscrow", + "SignerQuorum", { - "nth": 22, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 35, "type": "UInt32" } ], [ - "BondAmount", + "CancelAfter", { - "nth": 23, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 36, "type": "UInt32" } ], [ - "LoadFee", + "FinishAfter", { - "nth": 24, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 37, "type": "UInt32" } ], [ - "OfferSequence", + "SignerListID", { - "nth": 25, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 38, "type": "UInt32" } ], [ - "FirstLedgerSequence", + "SettleDelay", { - "nth": 26, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 39, "type": "UInt32" } ], [ - "LastLedgerSequence", + "TicketCount", { - "nth": 27, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 40, "type": "UInt32" } ], [ - "TransactionIndex", + "TicketSequence", { - "nth": 28, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 41, "type": "UInt32" } ], [ - "OperationLimit", + "NFTokenTaxon", { - "nth": 29, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 42, "type": "UInt32" } ], [ - "ReferenceFeeUnits", + "MintedNFTokens", { - "nth": 30, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 43, "type": "UInt32" } ], [ - "ReserveBase", + "BurnedNFTokens", { - "nth": 31, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 44, "type": "UInt32" } ], [ - "ReserveIncrement", + "HookStateCount", { - "nth": 32, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 45, "type": "UInt32" } ], [ - "SetFlag", + "EmitGeneration", { - "nth": 33, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 46, "type": "UInt32" } ], [ - "ClearFlag", + "VoteWeight", { - "nth": 34, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 48, "type": "UInt32" } ], [ - "SignerQuorum", - { - "nth": 35, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "CancelAfter", - { - "nth": 36, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "FinishAfter", - { - "nth": 37, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "SignerListID", - { - "nth": 38, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "SettleDelay", - { - "nth": 39, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "TicketCount", - { - "nth": 40, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "TicketSequence", - { - "nth": 41, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "NFTokenTaxon", - { - "nth": 42, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "MintedNFTokens", - { - "nth": 43, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "BurnedNFTokens", - { - "nth": 44, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "HookStateCount", - { - "nth": 45, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "EmitGeneration", + "FirstNFTokenSequence", { - "nth": 46, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "UInt32" - } - ], - [ - "VoteWeight", - { - "nth": 48, "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "UInt32" - } - ], - [ - "FirstNFTokenSequence", - { "nth": 50, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, "type": "UInt32" } ], [ "OracleDocumentID", { - "nth": 51, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 51, "type": "UInt32" } ], [ "IndexNext", { - "nth": 1, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 1, "type": "UInt64" } ], [ "IndexPrevious", { - "nth": 2, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 2, "type": "UInt64" } ], [ "BookNode", { - "nth": 3, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 3, "type": "UInt64" } ], [ "OwnerNode", { - "nth": 4, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 4, "type": "UInt64" } ], [ "BaseFee", { - "nth": 5, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 5, "type": "UInt64" } ], [ "ExchangeRate", { - "nth": 6, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 6, "type": "UInt64" } ], [ "LowNode", { - "nth": 7, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 7, "type": "UInt64" } ], [ "HighNode", { - "nth": 8, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 8, "type": "UInt64" } ], [ "DestinationNode", { - "nth": 9, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 9, "type": "UInt64" } ], [ "Cookie", { - "nth": 10, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 10, "type": "UInt64" } ], [ "ServerVersion", { - "nth": 11, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 11, "type": "UInt64" } ], [ "NFTokenOfferNode", { - "nth": 12, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 12, "type": "UInt64" } ], [ "EmitBurden", { - "nth": 13, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 13, "type": "UInt64" } ], [ "HookOn", { - "nth": 16, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 16, "type": "UInt64" } ], [ "HookInstructionCount", { - "nth": 17, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 17, "type": "UInt64" } ], [ "HookReturnCode", { - "nth": 18, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 18, "type": "UInt64" } ], [ "ReferenceCount", { - "nth": 19, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 19, "type": "UInt64" } ], [ "XChainClaimID", { - "nth": 20, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 20, "type": "UInt64" } ], [ "XChainAccountCreateCount", { - "nth": 21, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 21, "type": "UInt64" } ], [ "XChainAccountClaimCount", { - "nth": 22, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 22, "type": "UInt64" } ], [ "AssetPrice", { - "nth": 23, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 23, "type": "UInt64" } ], [ "MaximumAmount", { - "nth": 24, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 24, "type": "UInt64" } ], [ "OutstandingAmount", { - "nth": 25, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 25, "type": "UInt64" } ], [ "MPTAmount", { - "nth": 26, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 26, "type": "UInt64" } ], [ "IssuerNode", { - "nth": 27, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 27, "type": "UInt64" } ], [ "SubjectNode", { - "nth": 28, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 28, "type": "UInt64" } ], [ "EmailHash", { - "nth": 1, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 1, "type": "Hash128" } ], [ - "TakerPaysCurrency", + "LedgerHash", { - "nth": 1, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "Hash160" + "isVLEncoded": false, + "nth": 1, + "type": "Hash256" } ], [ - "TakerPaysIssuer", + "ParentHash", { - "nth": 2, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, - "type": "Hash160" - } - ], - [ - "TakerGetsCurrency", - { - "nth": 3, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Hash160" - } - ], - [ - "TakerGetsIssuer", - { - "nth": 4, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Hash160" - } - ], - [ - "MPTokenIssuanceID", - { - "nth": 1, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Hash192" - } - ], - [ - "LedgerHash", - { - "nth": 1, "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Hash256" - } - ], - [ - "ParentHash", - { "nth": 2, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, "type": "Hash256" } ], [ "TransactionHash", { - "nth": 3, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 3, "type": "Hash256" } ], [ "AccountHash", { - "nth": 4, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 4, "type": "Hash256" } ], [ "PreviousTxnID", { - "nth": 5, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 5, "type": "Hash256" } ], [ "LedgerIndex", { - "nth": 6, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 6, "type": "Hash256" } ], [ "WalletLocator", { - "nth": 7, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 7, "type": "Hash256" } ], [ "RootIndex", { - "nth": 8, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 8, "type": "Hash256" } ], [ "AccountTxnID", { - "nth": 9, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 9, "type": "Hash256" } ], [ "NFTokenID", { - "nth": 10, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 10, "type": "Hash256" } ], [ "EmitParentTxnID", { - "nth": 11, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 11, "type": "Hash256" } ], [ "EmitNonce", { - "nth": 12, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 12, "type": "Hash256" } ], [ "EmitHookHash", { - "nth": 13, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 13, "type": "Hash256" } ], [ "AMMID", { - "nth": 14, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 14, "type": "Hash256" } ], [ "BookDirectory", { - "nth": 16, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 16, "type": "Hash256" } ], [ "InvoiceID", { - "nth": 17, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 17, "type": "Hash256" } ], [ "Nickname", { - "nth": 18, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 18, "type": "Hash256" } ], [ "Amendment", { - "nth": 19, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 19, "type": "Hash256" } ], [ "Digest", { - "nth": 21, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 21, "type": "Hash256" } ], [ "Channel", { - "nth": 22, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 22, "type": "Hash256" } ], [ "ConsensusHash", { - "nth": 23, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 23, "type": "Hash256" } ], [ "CheckID", { - "nth": 24, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 24, "type": "Hash256" } ], [ "ValidatedHash", { - "nth": 25, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 25, "type": "Hash256" } ], [ "PreviousPageMin", { - "nth": 26, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 26, "type": "Hash256" } ], [ "NextPageMin", { - "nth": 27, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 27, "type": "Hash256" } ], [ "NFTokenBuyOffer", { - "nth": 28, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 28, "type": "Hash256" } ], [ "NFTokenSellOffer", { - "nth": 29, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 29, "type": "Hash256" } ], [ "HookStateKey", { - "nth": 30, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 30, "type": "Hash256" } ], [ "HookHash", { - "nth": 31, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 31, "type": "Hash256" } ], [ "HookNamespace", { - "nth": 32, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 32, "type": "Hash256" } ], [ "HookSetTxnID", { - "nth": 33, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 33, "type": "Hash256" } ], [ "DomainID", { - "nth": 34, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 34, "type": "Hash256" } ], [ "ParentBatchID", { - "nth": 35, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 35, "type": "Hash256" } ], [ - "Number", + "hash", { - "nth": 1, + "isSerialized": false, + "isSigningField": false, "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Number" + "nth": 257, + "type": "Hash256" } ], [ - "Amount", + "index", { - "nth": 1, + "isSerialized": false, + "isSigningField": false, "isVLEncoded": false, + "nth": 258, + "type": "Hash256" + } + ], + [ + "Amount", + { "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 1, "type": "Amount" } ], [ "Balance", { - "nth": 2, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 2, "type": "Amount" } ], [ "LimitAmount", { - "nth": 3, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 3, "type": "Amount" } ], [ "TakerPays", { - "nth": 4, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 4, "type": "Amount" } ], [ "TakerGets", { - "nth": 5, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 5, "type": "Amount" } ], [ "LowLimit", { - "nth": 6, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 6, "type": "Amount" } ], [ "HighLimit", { - "nth": 7, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 7, "type": "Amount" } ], [ "Fee", { - "nth": 8, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 8, "type": "Amount" } ], [ "SendMax", { - "nth": 9, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 9, "type": "Amount" } ], [ "DeliverMin", { - "nth": 10, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 10, "type": "Amount" } ], [ "Amount2", { - "nth": 11, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 11, "type": "Amount" } ], [ "BidMin", { - "nth": 12, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 12, "type": "Amount" } ], [ "BidMax", { - "nth": 13, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 13, "type": "Amount" } ], [ "MinimumOffer", { - "nth": 16, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 16, "type": "Amount" } ], [ "RippleEscrow", { - "nth": 17, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 17, "type": "Amount" } ], [ "DeliveredAmount", { - "nth": 18, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 18, "type": "Amount" } ], [ "NFTokenBrokerFee", { - "nth": 19, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 19, "type": "Amount" } ], [ "BaseFeeDrops", { - "nth": 22, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 22, "type": "Amount" } ], [ "ReserveBaseDrops", { - "nth": 23, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 23, "type": "Amount" } ], [ "ReserveIncrementDrops", { - "nth": 24, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 24, "type": "Amount" } ], [ "LPTokenOut", { - "nth": 25, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 25, "type": "Amount" } ], [ "LPTokenIn", { - "nth": 26, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 26, "type": "Amount" } ], [ "EPrice", { - "nth": 27, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 27, "type": "Amount" } ], [ "Price", { - "nth": 28, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 28, "type": "Amount" } ], [ "SignatureReward", { - "nth": 29, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 29, "type": "Amount" } ], [ "MinAccountCreateAmount", { - "nth": 30, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 30, "type": "Amount" } ], [ "LPTokenBalance", { - "nth": 31, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 31, "type": "Amount" } ], [ "PublicKey", { - "nth": 1, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 1, "type": "Blob" } ], [ "MessageKey", { - "nth": 2, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 2, "type": "Blob" } ], [ "SigningPubKey", { - "nth": 3, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 3, "type": "Blob" } ], [ "TxnSignature", { - "nth": 4, - "isVLEncoded": true, "isSerialized": true, "isSigningField": false, + "isVLEncoded": true, + "nth": 4, "type": "Blob" } ], [ "URI", { - "nth": 5, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 5, "type": "Blob" } ], [ "Signature", { - "nth": 6, - "isVLEncoded": true, "isSerialized": true, "isSigningField": false, + "isVLEncoded": true, + "nth": 6, "type": "Blob" } ], [ "Domain", { - "nth": 7, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 7, "type": "Blob" } ], [ "FundCode", { - "nth": 8, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 8, "type": "Blob" } ], [ "RemoveCode", { - "nth": 9, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 9, "type": "Blob" } ], [ "ExpireCode", { - "nth": 10, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 10, "type": "Blob" } ], [ "CreateCode", { - "nth": 11, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 11, "type": "Blob" } ], [ "MemoType", { - "nth": 12, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 12, "type": "Blob" } ], [ "MemoData", { - "nth": 13, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 13, "type": "Blob" } ], [ "MemoFormat", { - "nth": 14, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 14, "type": "Blob" } ], [ "Fulfillment", { - "nth": 16, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 16, "type": "Blob" } ], [ "Condition", { - "nth": 17, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 17, "type": "Blob" } ], [ "MasterSignature", { - "nth": 18, - "isVLEncoded": true, "isSerialized": true, "isSigningField": false, + "isVLEncoded": true, + "nth": 18, "type": "Blob" } ], [ "UNLModifyValidator", { - "nth": 19, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 19, "type": "Blob" } ], [ "ValidatorToDisable", { - "nth": 20, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 20, "type": "Blob" } ], [ "ValidatorToReEnable", { - "nth": 21, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 21, "type": "Blob" } ], [ "HookStateData", { - "nth": 22, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 22, "type": "Blob" } ], [ "HookReturnString", { - "nth": 23, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 23, "type": "Blob" } ], [ "HookParameterName", { - "nth": 24, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 24, "type": "Blob" } ], [ "HookParameterValue", { - "nth": 25, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 25, "type": "Blob" } ], [ "DIDDocument", { - "nth": 26, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 26, "type": "Blob" } ], [ "Data", { - "nth": 27, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 27, "type": "Blob" } ], [ "AssetClass", { - "nth": 28, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 28, "type": "Blob" } ], [ "Provider", { - "nth": 29, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 29, "type": "Blob" } ], [ "MPTokenMetadata", { - "nth": 30, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 30, "type": "Blob" } ], [ "CredentialType", { - "nth": 31, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 31, "type": "Blob" } ], [ "Account", { - "nth": 1, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 1, "type": "AccountID" } ], [ "Owner", { - "nth": 2, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 2, "type": "AccountID" } ], [ "Destination", { - "nth": 3, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 3, "type": "AccountID" } ], [ "Issuer", { - "nth": 4, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 4, "type": "AccountID" } ], [ "Authorize", { - "nth": 5, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 5, "type": "AccountID" } ], [ "Unauthorize", { - "nth": 6, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 6, "type": "AccountID" } ], [ "RegularKey", { - "nth": 8, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 8, "type": "AccountID" } ], [ "NFTokenMinter", { - "nth": 9, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 9, "type": "AccountID" } ], [ "EmitCallback", { - "nth": 10, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 10, "type": "AccountID" } ], [ "Holder", { - "nth": 11, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 11, "type": "AccountID" } ], [ "HookAccount", { - "nth": 16, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 16, "type": "AccountID" } ], [ "OtherChainSource", { - "nth": 18, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 18, "type": "AccountID" } ], [ "OtherChainDestination", { - "nth": 19, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 19, "type": "AccountID" } ], [ "AttestationSignerAccount", { - "nth": 20, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 20, "type": "AccountID" } ], [ "AttestationRewardAccount", { - "nth": 21, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 21, "type": "AccountID" } ], [ "LockingChainDoor", { - "nth": 22, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 22, "type": "AccountID" } ], [ "IssuingChainDoor", { - "nth": 23, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 23, "type": "AccountID" } ], [ "Subject", { - "nth": 24, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, + "isVLEncoded": true, + "nth": 24, "type": "AccountID" } ], [ - "Indexes", + "Number", { - "nth": 1, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, - "type": "Vector256" + "isVLEncoded": false, + "nth": 1, + "type": "Number" } ], [ - "Hashes", + "TransactionMetaData", { - "nth": 2, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, - "type": "Vector256" + "isVLEncoded": false, + "nth": 2, + "type": "STObject" } ], [ - "Amendments", + "CreatedNode", { - "nth": 3, - "isVLEncoded": true, "isSerialized": true, "isSigningField": true, - "type": "Vector256" - } - ], - [ - "NFTokenOffers", - { - "nth": 4, - "isVLEncoded": true, - "isSerialized": true, - "isSigningField": true, - "type": "Vector256" - } - ], - [ - "CredentialIDs", - { - "nth": 5, - "isVLEncoded": true, - "isSerialized": true, - "isSigningField": true, - "type": "Vector256" - } - ], - [ - "Paths", - { - "nth": 1, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "PathSet" - } - ], - [ - "BaseAsset", - { - "nth": 1, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Currency" - } - ], - [ - "QuoteAsset", - { - "nth": 2, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Currency" - } - ], - [ - "LockingChainIssue", - { - "nth": 1, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Issue" - } - ], - [ - "IssuingChainIssue", - { - "nth": 2, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Issue" - } - ], - [ - "Asset", - { - "nth": 3, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Issue" - } - ], - [ - "Asset2", - { - "nth": 4, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "Issue" - } - ], - [ - "XChainBridge", - { - "nth": 1, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "XChainBridge" - } - ], - [ - "TransactionMetaData", - { - "nth": 2, "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, - "type": "STObject" - } - ], - [ - "CreatedNode", - { "nth": 3, - "isVLEncoded": false, - "isSerialized": true, - "isSigningField": true, "type": "STObject" } ], [ "DeletedNode", { - "nth": 4, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 4, "type": "STObject" } ], [ "ModifiedNode", { - "nth": 5, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 5, "type": "STObject" } ], [ "PreviousFields", { - "nth": 6, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 6, "type": "STObject" } ], [ "FinalFields", { - "nth": 7, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 7, "type": "STObject" } ], [ "NewFields", { - "nth": 8, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 8, "type": "STObject" } ], [ "TemplateEntry", { - "nth": 9, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 9, "type": "STObject" } ], [ "Memo", { - "nth": 10, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 10, "type": "STObject" } ], [ "SignerEntry", { - "nth": 11, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 11, "type": "STObject" } ], [ "NFToken", { - "nth": 12, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 12, "type": "STObject" } ], [ "EmitDetails", { - "nth": 13, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 13, "type": "STObject" } ], [ "Hook", { - "nth": 14, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 14, "type": "STObject" } ], [ "Signer", { - "nth": 16, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 16, "type": "STObject" } ], [ "Majority", { - "nth": 18, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 18, "type": "STObject" } ], [ "DisabledValidator", { - "nth": 19, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 19, "type": "STObject" } ], [ "EmittedTxn", { - "nth": 20, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 20, "type": "STObject" } ], [ "HookExecution", { - "nth": 21, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 21, "type": "STObject" } ], [ "HookDefinition", { - "nth": 22, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 22, "type": "STObject" } ], [ "HookParameter", { - "nth": 23, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 23, "type": "STObject" } ], [ "HookGrant", { - "nth": 24, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 24, "type": "STObject" } ], [ "VoteEntry", { - "nth": 25, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 25, "type": "STObject" } ], [ "AuctionSlot", { - "nth": 26, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 26, "type": "STObject" } ], [ "AuthAccount", { - "nth": 27, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 27, "type": "STObject" } ], [ "XChainClaimProofSig", { - "nth": 28, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 28, "type": "STObject" } ], [ "XChainCreateAccountProofSig", { - "nth": 29, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 29, "type": "STObject" } ], [ "XChainClaimAttestationCollectionElement", { - "nth": 30, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 30, "type": "STObject" } ], [ "XChainCreateAccountAttestationCollectionElement", { - "nth": 31, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 31, "type": "STObject" } ], [ "PriceData", { - "nth": 32, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 32, "type": "STObject" } ], [ "Credential", { - "nth": 33, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 33, "type": "STObject" } ], [ "RawTransaction", { - "nth": 34, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 34, "type": "STObject" } ], [ "BatchSigner", { - "nth": 35, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 35, "type": "STObject" } ], [ "Signers", { - "nth": 3, - "isVLEncoded": false, "isSerialized": true, "isSigningField": false, + "isVLEncoded": false, + "nth": 3, "type": "STArray" } ], [ "SignerEntries", { - "nth": 4, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 4, "type": "STArray" } ], [ "Template", { - "nth": 5, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 5, "type": "STArray" } ], [ "Necessary", { - "nth": 6, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 6, "type": "STArray" } ], [ "Sufficient", { - "nth": 7, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 7, "type": "STArray" } ], [ "AffectedNodes", { - "nth": 8, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 8, "type": "STArray" } ], [ "Memos", { - "nth": 9, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 9, "type": "STArray" } ], [ "NFTokens", { - "nth": 10, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 10, "type": "STArray" } ], [ "Hooks", { - "nth": 11, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 11, "type": "STArray" } ], [ "VoteSlots", { - "nth": 12, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 12, "type": "STArray" } ], [ "Majorities", { - "nth": 16, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 16, "type": "STArray" } ], [ "DisabledValidators", { - "nth": 17, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 17, "type": "STArray" } ], [ "HookExecutions", { - "nth": 18, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 18, "type": "STArray" } ], [ "HookParameters", { - "nth": 19, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 19, "type": "STArray" } ], [ "HookGrants", { - "nth": 20, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 20, "type": "STArray" } ], [ "XChainClaimAttestations", { - "nth": 21, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 21, "type": "STArray" } ], [ "XChainCreateAccountAttestations", { - "nth": 22, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 22, "type": "STArray" } ], [ "PriceDataSeries", { - "nth": 24, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 24, "type": "STArray" } ], [ "AuthAccounts", { - "nth": 25, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 25, "type": "STArray" } ], [ "AuthorizeCredentials", { - "nth": 26, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 26, "type": "STArray" } ], [ "UnauthorizeCredentials", { - "nth": 27, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 27, "type": "STArray" } ], [ "AcceptedCredentials", { - "nth": 28, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 28, "type": "STArray" } ], [ "RawTransactions", { - "nth": 29, - "isVLEncoded": false, "isSerialized": true, "isSigningField": true, + "isVLEncoded": false, + "nth": 29, "type": "STArray" } ], [ "BatchSigners", { - "nth": 30, - "isVLEncoded": false, "isSerialized": true, "isSigningField": false, + "isVLEncoded": false, + "nth": 30, "type": "STArray" } - ] - ], - "TRANSACTION_RESULTS": { - "telLOCAL_ERROR": -399, - "telBAD_DOMAIN": -398, - "telBAD_PATH_COUNT": -397, - "telBAD_PUBLIC_KEY": -396, - "telFAILED_PROCESSING": -395, - "telINSUF_FEE_P": -394, - "telNO_DST_PARTIAL": -393, - "telCAN_NOT_QUEUE": -392, - "telCAN_NOT_QUEUE_BALANCE": -391, - "telCAN_NOT_QUEUE_BLOCKS": -390, - "telCAN_NOT_QUEUE_BLOCKED": -389, - "telCAN_NOT_QUEUE_FEE": -388, - "telCAN_NOT_QUEUE_FULL": -387, - "telWRONG_NETWORK": -386, - "telREQUIRES_NETWORK_ID": -385, - "telNETWORK_ID_MAKES_TX_NON_CANONICAL": -384, - "telENV_RPC_FAILED": -383, - - "temMALFORMED": -299, - "temBAD_AMOUNT": -298, - "temBAD_CURRENCY": -297, - "temBAD_EXPIRATION": -296, - "temBAD_FEE": -295, - "temBAD_ISSUER": -294, - "temBAD_LIMIT": -293, - "temBAD_OFFER": -292, - "temBAD_PATH": -291, - "temBAD_PATH_LOOP": -290, - "temBAD_REGKEY": -289, - "temBAD_SEND_XRP_LIMIT": -288, - "temBAD_SEND_XRP_MAX": -287, - "temBAD_SEND_XRP_NO_DIRECT": -286, - "temBAD_SEND_XRP_PARTIAL": -285, - "temBAD_SEND_XRP_PATHS": -284, - "temBAD_SEQUENCE": -283, - "temBAD_SIGNATURE": -282, - "temBAD_SRC_ACCOUNT": -281, - "temBAD_TRANSFER_RATE": -280, - "temDST_IS_SRC": -279, - "temDST_NEEDED": -278, - "temINVALID": -277, - "temINVALID_FLAG": -276, - "temREDUNDANT": -275, - "temRIPPLE_EMPTY": -274, - "temDISABLED": -273, - "temBAD_SIGNER": -272, - "temBAD_QUORUM": -271, - "temBAD_WEIGHT": -270, - "temBAD_TICK_SIZE": -269, - "temINVALID_ACCOUNT_ID": -268, - "temCANNOT_PREAUTH_SELF": -267, - "temINVALID_COUNT": -266, - "temUNCERTAIN": -265, - "temUNKNOWN": -264, - "temSEQ_AND_TICKET": -263, - "temBAD_NFTOKEN_TRANSFER_FEE": -262, - "temBAD_AMM_TOKENS": -261, - "temXCHAIN_EQUAL_DOOR_ACCOUNTS": -260, - "temXCHAIN_BAD_PROOF": -259, - "temXCHAIN_BRIDGE_BAD_ISSUES": -258, - "temXCHAIN_BRIDGE_NONDOOR_OWNER": -257, - "temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT": -256, - "temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT": -255, - "temEMPTY_DID": -254, - "temARRAY_EMPTY": -253, - "temARRAY_TOO_LARGE": -252, - "temBAD_TRANSFER_FEE": -251, - "temINVALID_INNER_BATCH": -250, - - "tefFAILURE": -199, - "tefALREADY": -198, - "tefBAD_ADD_AUTH": -197, - "tefBAD_AUTH": -196, - "tefBAD_LEDGER": -195, - "tefCREATED": -194, - "tefEXCEPTION": -193, - "tefINTERNAL": -192, - "tefNO_AUTH_REQUIRED": -191, - "tefPAST_SEQ": -190, - "tefWRONG_PRIOR": -189, - "tefMASTER_DISABLED": -188, - "tefMAX_LEDGER": -187, - "tefBAD_SIGNATURE": -186, - "tefBAD_QUORUM": -185, - "tefNOT_MULTI_SIGNING": -184, - "tefBAD_AUTH_MASTER": -183, - "tefINVARIANT_FAILED": -182, - "tefTOO_BIG": -181, - "tefNO_TICKET": -180, - "tefNFTOKEN_IS_NOT_TRANSFERABLE": -179, - "tefINVALID_LEDGER_FIX_TYPE": -178, - - "terRETRY": -99, - "terFUNDS_SPENT": -98, - "terINSUF_FEE_B": -97, - "terNO_ACCOUNT": -96, - "terNO_AUTH": -95, - "terNO_LINE": -94, - "terOWNERS": -93, - "terPRE_SEQ": -92, - "terLAST": -91, - "terNO_RIPPLE": -90, - "terQUEUED": -89, - "terPRE_TICKET": -88, - "terNO_AMM": -87, - - "tesSUCCESS": 0, - - "tecCLAIM": 100, - "tecPATH_PARTIAL": 101, - "tecUNFUNDED_ADD": 102, - "tecUNFUNDED_OFFER": 103, - "tecUNFUNDED_PAYMENT": 104, - "tecFAILED_PROCESSING": 105, - "tecDIR_FULL": 121, - "tecINSUF_RESERVE_LINE": 122, - "tecINSUF_RESERVE_OFFER": 123, - "tecNO_DST": 124, - "tecNO_DST_INSUF_XRP": 125, - "tecNO_LINE_INSUF_RESERVE": 126, - "tecNO_LINE_REDUNDANT": 127, - "tecPATH_DRY": 128, - "tecUNFUNDED": 129, - "tecNO_ALTERNATIVE_KEY": 130, - "tecNO_REGULAR_KEY": 131, - "tecOWNERS": 132, - "tecNO_ISSUER": 133, - "tecNO_AUTH": 134, - "tecNO_LINE": 135, - "tecINSUFF_FEE": 136, - "tecFROZEN": 137, - "tecNO_TARGET": 138, - "tecNO_PERMISSION": 139, - "tecNO_ENTRY": 140, - "tecINSUFFICIENT_RESERVE": 141, - "tecNEED_MASTER_KEY": 142, - "tecDST_TAG_NEEDED": 143, - "tecINTERNAL": 144, - "tecOVERSIZE": 145, - "tecCRYPTOCONDITION_ERROR": 146, - "tecINVARIANT_FAILED": 147, - "tecEXPIRED": 148, - "tecDUPLICATE": 149, - "tecKILLED": 150, - "tecHAS_OBLIGATIONS": 151, - "tecTOO_SOON": 152, - "tecHOOK_REJECTED": 153, - "tecMAX_SEQUENCE_REACHED": 154, - "tecNO_SUITABLE_NFTOKEN_PAGE": 155, - "tecNFTOKEN_BUY_SELL_MISMATCH": 156, - "tecNFTOKEN_OFFER_TYPE_MISMATCH": 157, - "tecCANT_ACCEPT_OWN_NFTOKEN_OFFER": 158, - "tecINSUFFICIENT_FUNDS": 159, - "tecOBJECT_NOT_FOUND": 160, - "tecINSUFFICIENT_PAYMENT": 161, - "tecUNFUNDED_AMM": 162, - "tecAMM_BALANCE": 163, - "tecAMM_FAILED": 164, - "tecAMM_INVALID_TOKENS": 165, - "tecAMM_EMPTY": 166, - "tecAMM_NOT_EMPTY": 167, - "tecAMM_ACCOUNT": 168, - "tecINCOMPLETE": 169, - "tecXCHAIN_BAD_TRANSFER_ISSUE": 170, - "tecXCHAIN_NO_CLAIM_ID": 171, - "tecXCHAIN_BAD_CLAIM_ID": 172, - "tecXCHAIN_CLAIM_NO_QUORUM": 173, - "tecXCHAIN_PROOF_UNKNOWN_KEY": 174, - "tecXCHAIN_CREATE_ACCOUNT_NONXRP_ISSUE": 175, - "tecXCHAIN_WRONG_CHAIN": 176, - "tecXCHAIN_REWARD_MISMATCH": 177, - "tecXCHAIN_NO_SIGNERS_LIST": 178, - "tecXCHAIN_SENDING_ACCOUNT_MISMATCH": 179, - "tecXCHAIN_INSUFF_CREATE_AMOUNT": 180, - "tecXCHAIN_ACCOUNT_CREATE_PAST": 181, - "tecXCHAIN_ACCOUNT_CREATE_TOO_MANY": 182, - "tecXCHAIN_PAYMENT_FAILED": 183, - "tecXCHAIN_SELF_COMMIT": 184, + ], + [ + "CloseResolution", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "UInt8" + } + ], + [ + "Method", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "UInt8" + } + ], + [ + "TransactionResult", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "UInt8" + } + ], + [ + "Scale", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "UInt8" + } + ], + [ + "AssetScale", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 5, + "type": "UInt8" + } + ], + [ + "TickSize", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 16, + "type": "UInt8" + } + ], + [ + "UNLModifyDisabling", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 17, + "type": "UInt8" + } + ], + [ + "HookResult", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 18, + "type": "UInt8" + } + ], + [ + "WasLockingChainSend", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 19, + "type": "UInt8" + } + ], + [ + "TakerPaysCurrency", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "Hash160" + } + ], + [ + "TakerPaysIssuer", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "Hash160" + } + ], + [ + "TakerGetsCurrency", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "Hash160" + } + ], + [ + "TakerGetsIssuer", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "Hash160" + } + ], + [ + "Paths", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "PathSet" + } + ], + [ + "Indexes", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 1, + "type": "Vector256" + } + ], + [ + "Hashes", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 2, + "type": "Vector256" + } + ], + [ + "Amendments", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 3, + "type": "Vector256" + } + ], + [ + "NFTokenOffers", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 4, + "type": "Vector256" + } + ], + [ + "CredentialIDs", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 5, + "type": "Vector256" + } + ], + [ + "MPTokenIssuanceID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "Hash192" + } + ], + [ + "LockingChainIssue", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "Issue" + } + ], + [ + "IssuingChainIssue", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "Issue" + } + ], + [ + "Asset", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "Issue" + } + ], + [ + "Asset2", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "Issue" + } + ], + [ + "XChainBridge", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "XChainBridge" + } + ], + [ + "BaseAsset", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "Currency" + } + ], + [ + "QuoteAsset", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "Currency" + } + ], + [ + "Transaction", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 257, + "type": "Transaction" + } + ], + [ + "LedgerEntry", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 257, + "type": "LedgerEntry" + } + ], + [ + "Validation", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 257, + "type": "Validation" + } + ], + [ + "Metadata", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 257, + "type": "Metadata" + } + ] + ], + "LEDGER_ENTRY_TYPES": { + "AMM": 121, + "AccountRoot": 97, + "Amendments": 102, + "Bridge": 105, + "Check": 67, + "Credential": 129, + "DID": 73, + "DepositPreauth": 112, + "DirectoryNode": 100, + "Escrow": 117, + "FeeSettings": 115, + "Invalid": -1, + "LedgerHashes": 104, + "MPToken": 127, + "MPTokenIssuance": 126, + "NFTokenOffer": 55, + "NFTokenPage": 80, + "NegativeUNL": 78, + "Offer": 111, + "Oracle": 128, + "PayChannel": 120, + "PermissionedDomain": 130, + "RippleState": 114, + "SignerList": 83, + "Ticket": 84, + "XChainOwnedClaimID": 113, + "XChainOwnedCreateAccountClaimID": 116 + }, + "TRANSACTION_RESULTS": { + "tecAMM_ACCOUNT": 168, + "tecAMM_BALANCE": 163, + "tecAMM_EMPTY": 166, + "tecAMM_FAILED": 164, + "tecAMM_INVALID_TOKENS": 165, + "tecAMM_NOT_EMPTY": 167, + "tecARRAY_EMPTY": 190, + "tecARRAY_TOO_LARGE": 191, + "tecBAD_CREDENTIALS": 193, + "tecCANT_ACCEPT_OWN_NFTOKEN_OFFER": 158, + "tecCLAIM": 100, + "tecCRYPTOCONDITION_ERROR": 146, + "tecDIR_FULL": 121, + "tecDST_TAG_NEEDED": 143, + "tecDUPLICATE": 149, + "tecEMPTY_DID": 187, + "tecEXPIRED": 148, + "tecFAILED_PROCESSING": 105, + "tecFROZEN": 137, + "tecHAS_OBLIGATIONS": 151, + "tecHOOK_REJECTED": 153, + "tecINCOMPLETE": 169, + "tecINSUFFICIENT_FUNDS": 159, + "tecINSUFFICIENT_PAYMENT": 161, + "tecINSUFFICIENT_RESERVE": 141, + "tecINSUFF_FEE": 136, + "tecINSUF_RESERVE_LINE": 122, + "tecINSUF_RESERVE_OFFER": 123, + "tecINTERNAL": 144, + "tecINVALID_UPDATE_TIME": 188, + "tecINVARIANT_FAILED": 147, + "tecKILLED": 150, + "tecLOCKED": 192, + "tecMAX_SEQUENCE_REACHED": 154, + "tecNEED_MASTER_KEY": 142, + "tecNFTOKEN_BUY_SELL_MISMATCH": 156, + "tecNFTOKEN_OFFER_TYPE_MISMATCH": 157, + "tecNO_ALTERNATIVE_KEY": 130, + "tecNO_AUTH": 134, + "tecNO_DST": 124, + "tecNO_DST_INSUF_XRP": 125, + "tecNO_ENTRY": 140, + "tecNO_ISSUER": 133, + "tecNO_LINE": 135, + "tecNO_LINE_INSUF_RESERVE": 126, + "tecNO_LINE_REDUNDANT": 127, + "tecNO_PERMISSION": 139, + "tecNO_REGULAR_KEY": 131, + "tecNO_SUITABLE_NFTOKEN_PAGE": 155, + "tecNO_TARGET": 138, + "tecOBJECT_NOT_FOUND": 160, + "tecOVERSIZE": 145, + "tecOWNERS": 132, + "tecPATH_DRY": 128, + "tecPATH_PARTIAL": 101, + "tecTOKEN_PAIR_NOT_FOUND": 189, + "tecTOO_SOON": 152, + "tecUNFUNDED": 129, + "tecUNFUNDED_ADD": 102, + "tecUNFUNDED_AMM": 162, + "tecUNFUNDED_OFFER": 103, + "tecUNFUNDED_PAYMENT": 104, + "tecXCHAIN_ACCOUNT_CREATE_PAST": 181, + "tecXCHAIN_ACCOUNT_CREATE_TOO_MANY": 182, + "tecXCHAIN_BAD_CLAIM_ID": 172, "tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR": 185, + "tecXCHAIN_BAD_TRANSFER_ISSUE": 170, + "tecXCHAIN_CLAIM_NO_QUORUM": 173, "tecXCHAIN_CREATE_ACCOUNT_DISABLED": 186, - "tecEMPTY_DID": 187, - "tecINVALID_UPDATE_TIME": 188, - "tecTOKEN_PAIR_NOT_FOUND": 189, - "tecARRAY_EMPTY": 190, - "tecARRAY_TOO_LARGE": 191, - "tecLOCKED": 192, - "tecBAD_CREDENTIALS": 193 + "tecXCHAIN_CREATE_ACCOUNT_NONXRP_ISSUE": 175, + "tecXCHAIN_INSUFF_CREATE_AMOUNT": 180, + "tecXCHAIN_NO_CLAIM_ID": 171, + "tecXCHAIN_NO_SIGNERS_LIST": 178, + "tecXCHAIN_PAYMENT_FAILED": 183, + "tecXCHAIN_PROOF_UNKNOWN_KEY": 174, + "tecXCHAIN_REWARD_MISMATCH": 177, + "tecXCHAIN_SELF_COMMIT": 184, + "tecXCHAIN_SENDING_ACCOUNT_MISMATCH": 179, + "tecXCHAIN_WRONG_CHAIN": 176, + + "tefALREADY": -198, + "tefBAD_ADD_AUTH": -197, + "tefBAD_AUTH": -196, + "tefBAD_AUTH_MASTER": -183, + "tefBAD_LEDGER": -195, + "tefBAD_QUORUM": -185, + "tefBAD_SIGNATURE": -186, + "tefCREATED": -194, + "tefEXCEPTION": -193, + "tefFAILURE": -199, + "tefINTERNAL": -192, + "tefINVALID_LEDGER_FIX_TYPE": -178, + "tefINVARIANT_FAILED": -182, + "tefMASTER_DISABLED": -188, + "tefMAX_LEDGER": -187, + "tefNFTOKEN_IS_NOT_TRANSFERABLE": -179, + "tefNOT_MULTI_SIGNING": -184, + "tefNO_AUTH_REQUIRED": -191, + "tefNO_TICKET": -180, + "tefPAST_SEQ": -190, + "tefTOO_BIG": -181, + "tefWRONG_PRIOR": -189, + + "telBAD_DOMAIN": -398, + "telBAD_PATH_COUNT": -397, + "telBAD_PUBLIC_KEY": -396, + "telCAN_NOT_QUEUE": -392, + "telCAN_NOT_QUEUE_BALANCE": -391, + "telCAN_NOT_QUEUE_BLOCKED": -389, + "telCAN_NOT_QUEUE_BLOCKS": -390, + "telCAN_NOT_QUEUE_FEE": -388, + "telCAN_NOT_QUEUE_FULL": -387, + "telENV_RPC_FAILED": -383, + "telFAILED_PROCESSING": -395, + "telINSUF_FEE_P": -394, + "telLOCAL_ERROR": -399, + "telNETWORK_ID_MAKES_TX_NON_CANONICAL": -384, + "telNO_DST_PARTIAL": -393, + "telREQUIRES_NETWORK_ID": -385, + "telWRONG_NETWORK": -386, + + "temARRAY_EMPTY": -253, + "temARRAY_TOO_LARGE": -252, + "temBAD_AMM_TOKENS": -261, + "temBAD_AMOUNT": -298, + "temBAD_CURRENCY": -297, + "temBAD_EXPIRATION": -296, + "temBAD_FEE": -295, + "temBAD_ISSUER": -294, + "temBAD_LIMIT": -293, + "temBAD_NFTOKEN_TRANSFER_FEE": -262, + "temBAD_OFFER": -292, + "temBAD_PATH": -291, + "temBAD_PATH_LOOP": -290, + "temBAD_QUORUM": -271, + "temBAD_REGKEY": -289, + "temBAD_SEND_XRP_LIMIT": -288, + "temBAD_SEND_XRP_MAX": -287, + "temBAD_SEND_XRP_NO_DIRECT": -286, + "temBAD_SEND_XRP_PARTIAL": -285, + "temBAD_SEND_XRP_PATHS": -284, + "temBAD_SEQUENCE": -283, + "temBAD_SIGNATURE": -282, + "temBAD_SIGNER": -272, + "temBAD_SRC_ACCOUNT": -281, + "temBAD_TICK_SIZE": -269, + "temBAD_TRANSFER_FEE": -251, + "temBAD_TRANSFER_RATE": -280, + "temBAD_WEIGHT": -270, + "temCANNOT_PREAUTH_SELF": -267, + "temDISABLED": -273, + "temDST_IS_SRC": -279, + "temDST_NEEDED": -278, + "temEMPTY_DID": -254, + "temINVALID": -277, + "temINVALID_ACCOUNT_ID": -268, + "temINVALID_COUNT": -266, + "temINVALID_FLAG": -276, + "temINVALID_INNER_BATCH": -250, + "temMALFORMED": -299, + "temREDUNDANT": -275, + "temRIPPLE_EMPTY": -274, + "temSEQ_AND_TICKET": -263, + "temUNCERTAIN": -265, + "temUNKNOWN": -264, + "temXCHAIN_BAD_PROOF": -259, + "temXCHAIN_BRIDGE_BAD_ISSUES": -258, + "temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT": -256, + "temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT": -255, + "temXCHAIN_BRIDGE_NONDOOR_OWNER": -257, + "temXCHAIN_EQUAL_DOOR_ACCOUNTS": -260, + + "terFUNDS_SPENT": -98, + "terINSUF_FEE_B": -97, + "terLAST": -91, + "terNO_ACCOUNT": -96, + "terNO_AMM": -87, + "terNO_AUTH": -95, + "terNO_LINE": -94, + "terNO_RIPPLE": -90, + "terOWNERS": -93, + "terPRE_SEQ": -92, + "terPRE_TICKET": -88, + "terQUEUED": -89, + "terRETRY": -99, + + "tesSUCCESS": 0 }, "TRANSACTION_TYPES": { - "Invalid": -1, - "Payment": 0, - "EscrowCreate": 1, - "EscrowFinish": 2, - "AccountSet": 3, - "EscrowCancel": 4, - "SetRegularKey": 5, - "OfferCreate": 7, - "OfferCancel": 8, - "TicketCreate": 10, - "SignerListSet": 12, - "PaymentChannelCreate": 13, - "PaymentChannelFund": 14, - "PaymentChannelClaim": 15, - "CheckCreate": 16, - "CheckCash": 17, - "CheckCancel": 18, - "DepositPreauth": 19, - "TrustSet": 20, - "AccountDelete": 21, - "NFTokenMint": 25, - "NFTokenBurn": 26, - "NFTokenCreateOffer": 27, - "NFTokenCancelOffer": 28, - "NFTokenAcceptOffer": 29, - "Clawback": 30, + "AMMBid": 39, "AMMClawback": 31, "AMMCreate": 35, + "AMMDelete": 40, "AMMDeposit": 36, - "AMMWithdraw": 37, "AMMVote": 38, - "AMMBid": 39, - "AMMDelete": 40, - "XChainCreateClaimID": 41, - "XChainCommit": 42, - "XChainClaim": 43, - "XChainAccountCreateCommit": 44, - "XChainAddClaimAttestation": 45, - "XChainAddAccountCreateAttestation": 46, - "XChainModifyBridge": 47, - "XChainCreateBridge": 48, - "DIDSet": 49, + "AMMWithdraw": 37, + "AccountDelete": 21, + "AccountSet": 3, + "Batch": 64, + "CheckCancel": 18, + "CheckCash": 17, + "CheckCreate": 16, + "Clawback": 30, + "CredentialAccept": 59, + "CredentialCreate": 58, + "CredentialDelete": 60, "DIDDelete": 50, - "OracleSet": 51, - "OracleDelete": 52, + "DIDSet": 49, + "DepositPreauth": 19, + "EnableAmendment": 100, + "EscrowCancel": 4, + "EscrowCreate": 1, + "EscrowFinish": 2, + "Invalid": -1, "LedgerStateFix": 53, + "MPTokenAuthorize": 57, "MPTokenIssuanceCreate": 54, "MPTokenIssuanceDestroy": 55, "MPTokenIssuanceSet": 56, - "MPTokenAuthorize": 57, - "CredentialCreate": 58, - "CredentialAccept": 59, - "CredentialDelete": 60, + "NFTokenAcceptOffer": 29, + "NFTokenBurn": 26, + "NFTokenCancelOffer": 28, + "NFTokenCreateOffer": 27, + "NFTokenMint": 25, "NFTokenModify": 61, - "PermissionedDomainSet": 62, + "OfferCancel": 8, + "OfferCreate": 7, + "OracleDelete": 52, + "OracleSet": 51, + "Payment": 0, + "PaymentChannelClaim": 15, + "PaymentChannelCreate": 13, + "PaymentChannelFund": 14, "PermissionedDomainDelete": 63, - "Batch": 64, - "EnableAmendment": 100, + "PermissionedDomainSet": 62, "SetFee": 101, - "UNLModify": 102 + "SetRegularKey": 5, + "SignerListSet": 12, + "TicketCreate": 10, + "TrustSet": 20, + "UNLModify": 102, + "XChainAccountCreateCommit": 44, + "XChainAddAccountCreateAttestation": 46, + "XChainAddClaimAttestation": 45, + "XChainClaim": 43, + "XChainCommit": 42, + "XChainCreateBridge": 48, + "XChainCreateClaimID": 41, + "XChainModifyBridge": 47 + }, + "TYPES": { + "AccountID": 8, + "Amount": 6, + "Blob": 7, + "Currency": 26, + "Done": -1, + "Hash128": 4, + "Hash160": 17, + "Hash192": 21, + "Hash256": 5, + "Issue": 24, + "LedgerEntry": 10002, + "Metadata": 10004, + "NotPresent": 0, + "Number": 9, + "PathSet": 18, + "STArray": 15, + "STObject": 14, + "Transaction": 10001, + "UInt16": 1, + "UInt32": 2, + "UInt384": 22, + "UInt512": 23, + "UInt64": 3, + "UInt8": 16, + "UInt96": 20, + "Unknown": -2, + "Validation": 10003, + "Vector256": 19, + "XChainBridge": 25 } } From f06e83cb434f7bcf962e8d59fbcc51f160ad2c8a Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 6 Feb 2025 15:52:48 -0800 Subject: [PATCH 49/73] fix error --- packages/xrpl/src/models/utils/flags.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xrpl/src/models/utils/flags.ts b/packages/xrpl/src/models/utils/flags.ts index b72f8e9d4c..eff6f7c689 100644 --- a/packages/xrpl/src/models/utils/flags.ts +++ b/packages/xrpl/src/models/utils/flags.ts @@ -8,7 +8,7 @@ import { AccountSetTfFlags } from '../transactions/accountSet' import { AMMDepositFlags } from '../transactions/AMMDeposit' import { AMMWithdrawFlags } from '../transactions/AMMWithdraw' import { BatchFlags } from '../transactions/batch' -import { GlobalFlags, GlobalFlagsInterface } from '../transactions/common' +import { GlobalFlags } from '../transactions/common' import { MPTokenAuthorizeFlags } from '../transactions/MPTokenAuthorize' import { MPTokenIssuanceCreateFlags } from '../transactions/MPTokenIssuanceCreate' import { MPTokenIssuanceSetFlags } from '../transactions/MPTokenIssuanceSet' From dd36b47296bd73ae8c6fe0130949772bb9b13298 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 6 Feb 2025 16:06:17 -0800 Subject: [PATCH 50/73] minor cleanup --- packages/xrpl/test/integration/transactions/batch.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/xrpl/test/integration/transactions/batch.test.ts b/packages/xrpl/test/integration/transactions/batch.test.ts index e5318fbc8e..3ca8d1b7f0 100644 --- a/packages/xrpl/test/integration/transactions/batch.test.ts +++ b/packages/xrpl/test/integration/transactions/batch.test.ts @@ -85,7 +85,6 @@ describe('Batch', function () { TransactionType: 'Batch', Account: testContext.wallet.classicAddress, Flags: BatchFlags.tfAllOrNothing, - Fee: '50', RawTransactions: [ { RawTransaction: { From 1f7c48c614da24174f1bfbd1c9531f78dacf1d80 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Mon, 10 Feb 2025 09:51:13 -0800 Subject: [PATCH 51/73] update vscode settings --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 6e4555a206..216e9617cc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,6 +12,7 @@ "multisign", "multisigned", "multisigning", + "Permissioned", "preauthorization", "rippletest", "secp256k1", From 1773246ad9aa489ea740845e966be7a6a9cff769 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Mon, 10 Feb 2025 09:53:07 -0800 Subject: [PATCH 52/73] fix linter --- packages/xrpl/src/models/transactions/common.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index a8e846a3a6..c659662500 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -575,7 +575,6 @@ export function containsDuplicates( if (isAuthorizeCredentialArray(objectList)) { for (const item of objectList) { const key = `${item.Credential.Issuer}-${item.Credential.CredentialType}` - // eslint-disable-next-line max-depth -- necessary to check for type-guards if (seen.has(key)) { return true } From 27a39bfd7f2a1b28f8b70030fe4b0cb3d133b83d Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Mon, 10 Feb 2025 10:30:01 -0800 Subject: [PATCH 53/73] fix history --- packages/xrpl/HISTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xrpl/HISTORY.md b/packages/xrpl/HISTORY.md index 99de2569ee..78cdbe3386 100644 --- a/packages/xrpl/HISTORY.md +++ b/packages/xrpl/HISTORY.md @@ -7,7 +7,7 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr ### Added * Adds utility function `convertTxFlagsToNumber` * Implementation of XLS-80d PermissionedDomain feature. -* Support for the `simulate` RPC ([XLS-69d](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069-simulate)) +* Support for the `simulate` RPC ([XLS-69](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069-simulate)) * Add support for `Batch` amendment (XLS-56). ### Changed From 357b5b04639bb027edba0472e1d7c8ef7e9a78da Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 12 Feb 2025 12:40:21 -0500 Subject: [PATCH 54/73] fix tests --- packages/xrpl/src/Wallet/index.ts | 4 ++-- packages/xrpl/test/integration/transactions/batch.test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index db1f4a313b..03abb68f10 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -416,9 +416,8 @@ export class Wallet { const txToSignAndEncode = { ...tx } - txToSignAndEncode.SigningPubKey = multisignAddress ? '' : this.publicKey - if (multisignAddress) { + txToSignAndEncode.SigningPubKey = '' const signer = { Account: multisignAddress, SigningPubKey: this.publicKey, @@ -430,6 +429,7 @@ export class Wallet { } txToSignAndEncode.Signers = [{ Signer: signer }] } else { + txToSignAndEncode.SigningPubKey = this.publicKey txToSignAndEncode.TxnSignature = computeSignature( txToSignAndEncode, this.privateKey, diff --git a/packages/xrpl/test/integration/transactions/batch.test.ts b/packages/xrpl/test/integration/transactions/batch.test.ts index 3ca8d1b7f0..0bfe150727 100644 --- a/packages/xrpl/test/integration/transactions/batch.test.ts +++ b/packages/xrpl/test/integration/transactions/batch.test.ts @@ -104,7 +104,7 @@ describe('Batch', function () { }, ], } - const autofilled = await testContext.client.autofill(tx) + const autofilled = await testContext.client.autofill(tx, 2) signMultiBatch(wallet2, autofilled) await testBatchTransaction(autofilled, testContext.wallet) }, From 23e3e07ba4259dee5b882a671a7f493a084af556 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 13 Feb 2025 13:58:30 -0500 Subject: [PATCH 55/73] fix build issue --- packages/xrpl/src/models/transactions/AMMClawback.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/xrpl/src/models/transactions/AMMClawback.ts b/packages/xrpl/src/models/transactions/AMMClawback.ts index 7ef4b2ca85..cd673a4d11 100644 --- a/packages/xrpl/src/models/transactions/AMMClawback.ts +++ b/packages/xrpl/src/models/transactions/AMMClawback.ts @@ -4,7 +4,7 @@ import { Currency, IssuedCurrency, IssuedCurrencyAmount } from '../common' import { Account, BaseTransaction, - GlobalFlags, + GlobalFlagsInterface, isAccount, isAmount, isCurrency, @@ -28,7 +28,7 @@ export enum AMMClawbackFlags { * * @category Transaction Flags */ -export interface AMMClawbackFlagsInterface extends GlobalFlags { +export interface AMMClawbackFlagsInterface extends GlobalFlagsInterface { tfClawTwoAssets?: boolean } From ae20b6bf2c47f64419f4cfc172bf67db727170a6 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 13 Feb 2025 14:01:55 -0500 Subject: [PATCH 56/73] bump versions for beta --- packages/ripple-address-codec/package.json | 2 +- packages/ripple-binary-codec/package.json | 2 +- packages/ripple-keypairs/package.json | 2 +- packages/secret-numbers/package.json | 2 +- packages/xrpl/package.json | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/ripple-address-codec/package.json b/packages/ripple-address-codec/package.json index bd791c797a..9fa164b9f0 100644 --- a/packages/ripple-address-codec/package.json +++ b/packages/ripple-address-codec/package.json @@ -11,7 +11,7 @@ "license": "ISC", "dependencies": { "@scure/base": "^1.1.3", - "@xrplf/isomorphic": "^1.0.0" + "@xrplf/isomorphic": "^1.0.1" }, "keywords": [ "ripple", diff --git a/packages/ripple-binary-codec/package.json b/packages/ripple-binary-codec/package.json index a1a26762ea..bdc6213156 100644 --- a/packages/ripple-binary-codec/package.json +++ b/packages/ripple-binary-codec/package.json @@ -1,6 +1,6 @@ { "name": "ripple-binary-codec", - "version": "2.2.0", + "version": "2.3.0-batch.0", "description": "XRP Ledger binary codec", "files": [ "dist/*", diff --git a/packages/ripple-keypairs/package.json b/packages/ripple-keypairs/package.json index b5899b1f50..62de4afbcb 100644 --- a/packages/ripple-keypairs/package.json +++ b/packages/ripple-keypairs/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@noble/curves": "^1.0.0", - "@xrplf/isomorphic": "^1.0.0", + "@xrplf/isomorphic": "^1.0.1", "ripple-address-codec": "^5.0.0" }, "keywords": [ diff --git a/packages/secret-numbers/package.json b/packages/secret-numbers/package.json index 4eb6c0cfd6..facb8a5270 100644 --- a/packages/secret-numbers/package.json +++ b/packages/secret-numbers/package.json @@ -29,7 +29,7 @@ "test": "test" }, "dependencies": { - "@xrplf/isomorphic": "^1.0.0", + "@xrplf/isomorphic": "^1.0.1", "ripple-keypairs": "^2.0.0" }, "prettier": "@xrplf/prettier-config", diff --git a/packages/xrpl/package.json b/packages/xrpl/package.json index 88e485aed0..ab7d86dbff 100644 --- a/packages/xrpl/package.json +++ b/packages/xrpl/package.json @@ -1,6 +1,6 @@ { "name": "xrpl", - "version": "4.1.0", + "version": "4.2.0-batch.0", "license": "ISC", "description": "A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser", "files": [ @@ -29,7 +29,7 @@ "bignumber.js": "^9.0.0", "eventemitter3": "^5.0.1", "ripple-address-codec": "^5.0.0", - "ripple-binary-codec": "^2.2.0", + "ripple-binary-codec": "^2.3.0-batch.0", "ripple-keypairs": "^2.0.0" }, "devDependencies": { From 3c563434d49d4d656f8b62933f035082733af560 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 13 Feb 2025 14:04:16 -0500 Subject: [PATCH 57/73] update packagelock --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index ad65201f11..0baf86ed65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14500,14 +14500,14 @@ "license": "ISC", "dependencies": { "@scure/base": "^1.1.3", - "@xrplf/isomorphic": "^1.0.0" + "@xrplf/isomorphic": "^1.0.1" }, "engines": { "node": ">= 18" } }, "packages/ripple-binary-codec": { - "version": "2.2.0", + "version": "2.3.0-batch.0", "license": "ISC", "dependencies": { "@xrplf/isomorphic": "^1.0.1", @@ -14523,7 +14523,7 @@ "license": "ISC", "dependencies": { "@noble/curves": "^1.0.0", - "@xrplf/isomorphic": "^1.0.0", + "@xrplf/isomorphic": "^1.0.1", "ripple-address-codec": "^5.0.0" }, "engines": { @@ -14535,12 +14535,12 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@xrplf/isomorphic": "^1.0.0", + "@xrplf/isomorphic": "^1.0.1", "ripple-keypairs": "^2.0.0" } }, "packages/xrpl": { - "version": "4.1.0", + "version": "4.2.0-batch.0", "license": "ISC", "dependencies": { "@scure/bip32": "^1.3.1", @@ -14550,7 +14550,7 @@ "bignumber.js": "^9.0.0", "eventemitter3": "^5.0.1", "ripple-address-codec": "^5.0.0", - "ripple-binary-codec": "^2.2.0", + "ripple-binary-codec": "^2.3.0-batch.0", "ripple-keypairs": "^2.0.0" }, "devDependencies": { From c4a1b21f2b8a1af6e8ed99e7676c26d308bda163 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 26 Mar 2025 14:57:50 -0400 Subject: [PATCH 58/73] update package-lock --- package-lock.json | 489 ++++++++++++++-------------------------------- 1 file changed, 152 insertions(+), 337 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3820859dc7..f4f080080e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -787,9 +787,8 @@ }, "node_modules/@eslint/js": { "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -801,9 +800,8 @@ }, "node_modules/@gerrit0/mini-shiki": { "version": "1.24.4", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-1.24.4.tgz", - "integrity": "sha512-YEHW1QeAg6UmxEmswiQbOVEg1CW22b1XUD/lNTliOsu0LD0wqoyleFMnmbTp697QE0pcadQiR5cVtbbAPncvpw==", "dev": true, + "license": "MIT", "dependencies": { "@shikijs/engine-oniguruma": "^1.24.2", "@shikijs/types": "^1.24.2", @@ -812,10 +810,8 @@ }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -839,10 +835,8 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@hutson/parse-repository-url": { "version": "3.0.2", @@ -1232,8 +1226,6 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, "license": "MIT", "dependencies": { @@ -1255,8 +1247,6 @@ }, "node_modules/@jridgewell/set-array": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "license": "MIT", "engines": { @@ -1265,8 +1255,6 @@ }, "node_modules/@jridgewell/source-map": { "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1281,8 +1269,6 @@ }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2300,8 +2286,6 @@ }, "node_modules/@noble/curves": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", - "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", "license": "MIT", "dependencies": { "@noble/hashes": "1.7.1" @@ -2315,8 +2299,6 @@ }, "node_modules/@noble/hashes": { "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", - "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -2622,14 +2604,11 @@ }, "node_modules/@rtsao/scc": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@scure/base": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.4.tgz", - "integrity": "sha512-5Yy9czTO47mqz+/J8GM6GIId4umdCk1wc1q8rKERQulIoc8VP9pzDcghv10Tl2E7R96ZUx/PhND3ESYUQX8NuQ==", "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" @@ -2637,8 +2616,6 @@ }, "node_modules/@scure/bip32": { "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", - "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", "license": "MIT", "dependencies": { "@noble/curves": "~1.8.1", @@ -2651,8 +2628,6 @@ }, "node_modules/@scure/bip39": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", - "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", "license": "MIT", "dependencies": { "@noble/hashes": "~1.7.1", @@ -2664,9 +2639,8 @@ }, "node_modules/@shikijs/engine-oniguruma": { "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.25.1.tgz", - "integrity": "sha512-iKPMh3H+0USHtWfZ1irfMTH6tGmIUFSnqt3E2K8BgI1VEsqiPh0RYkG2WTwzNiM1/WHN4FzYx/nrKR7PDHiRyw==", "dev": true, + "license": "MIT", "dependencies": { "@shikijs/types": "1.25.1", "@shikijs/vscode-textmate": "^9.3.1" @@ -2674,9 +2648,8 @@ }, "node_modules/@shikijs/types": { "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.25.1.tgz", - "integrity": "sha512-dceqFUoO95eY4tpOj3OGq8wE8EgJ4ey6Me1HQEu5UbwIYszFndEll/bjlB8Kp9wl4fx3uM7n4+y9XCYuDBmcXA==", "dev": true, + "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^9.3.1", "@types/hast": "^3.0.4" @@ -2684,9 +2657,8 @@ }, "node_modules/@shikijs/vscode-textmate": { "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.3.1.tgz", - "integrity": "sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sinclair/typebox": { "version": "0.27.8", @@ -2799,9 +2771,8 @@ }, "node_modules/@types/eslint": { "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -2809,9 +2780,8 @@ }, "node_modules/@types/eslint-scope": { "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -2819,9 +2789,8 @@ }, "node_modules/@types/estree": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/graceful-fs": { "version": "4.1.7", @@ -2833,9 +2802,8 @@ }, "node_modules/@types/hast": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/unist": "*" } @@ -2863,9 +2831,8 @@ }, "node_modules/@types/jest": { "version": "29.5.14", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", - "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -2883,8 +2850,6 @@ }, "node_modules/@types/lodash": { "version": "4.17.15", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==", "dev": true, "license": "MIT" }, @@ -2900,9 +2865,8 @@ }, "node_modules/@types/node": { "version": "18.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", - "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } @@ -2929,14 +2893,11 @@ }, "node_modules/@types/unist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/ws": { "version": "8.5.14", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz", - "integrity": "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==", "dev": true, "license": "MIT", "dependencies": { @@ -3143,9 +3104,8 @@ }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" @@ -3153,27 +3113,23 @@ }, "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", @@ -3182,15 +3138,13 @@ }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -3200,33 +3154,29 @@ }, "node_modules/@webassemblyjs/ieee754": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -3240,9 +3190,8 @@ }, "node_modules/@webassemblyjs/wasm-gen": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", @@ -3253,9 +3202,8 @@ }, "node_modules/@webassemblyjs/wasm-opt": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -3265,9 +3213,8 @@ }, "node_modules/@webassemblyjs/wasm-parser": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", @@ -3279,9 +3226,8 @@ }, "node_modules/@webassemblyjs/wast-printer": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" @@ -3289,9 +3235,8 @@ }, "node_modules/@webpack-cli/configtest": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", - "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18.12.0" }, @@ -3302,9 +3247,8 @@ }, "node_modules/@webpack-cli/info": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", - "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=18.12.0" }, @@ -3315,9 +3259,8 @@ }, "node_modules/@webpack-cli/serve": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", - "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", "dev": true, + "license": "MIT", "engines": { "node": ">=18.12.0" }, @@ -3370,15 +3313,13 @@ }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/abbrev": { "version": "1.1.1", @@ -3399,9 +3340,8 @@ }, "node_modules/acorn": { "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3481,8 +3421,6 @@ }, "node_modules/ajv-formats": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, "license": "MIT", "dependencies": { @@ -3499,8 +3437,6 @@ }, "node_modules/ajv-formats/node_modules/ajv": { "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { @@ -3516,8 +3452,6 @@ }, "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, @@ -3647,9 +3581,8 @@ }, "node_modules/array-buffer-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "is-array-buffer": "^3.0.4" @@ -3676,9 +3609,8 @@ }, "node_modules/array-includes": { "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -3704,9 +3636,8 @@ }, "node_modules/array.prototype.findlastindex": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -3789,9 +3720,8 @@ }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.5", @@ -3854,9 +3784,8 @@ }, "node_modules/async": { "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/asynciterator.prototype": { "version": "1.0.0", @@ -3882,9 +3811,8 @@ }, "node_modules/available-typed-arrays": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -4148,8 +4076,6 @@ }, "node_modules/browserslist": { "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, "funding": [ { @@ -4165,6 +4091,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001669", "electron-to-chromium": "^1.5.41", @@ -4277,9 +4204,8 @@ }, "node_modules/call-bind": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -4328,8 +4254,6 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001680", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", - "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", "dev": true, "funding": [ { @@ -4344,7 +4268,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/caseless": { "version": "0.12.0", @@ -4627,8 +4552,6 @@ }, "node_modules/commander": { "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, "license": "MIT" }, @@ -5016,9 +4939,8 @@ }, "node_modules/data-view-buffer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -5033,9 +4955,8 @@ }, "node_modules/data-view-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -5050,9 +4971,8 @@ }, "node_modules/data-view-byte-offset": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -5199,9 +5119,8 @@ }, "node_modules/define-data-property": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -5216,9 +5135,8 @@ }, "node_modules/define-properties": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -5389,9 +5307,8 @@ }, "node_modules/ejs": { "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" }, @@ -5404,9 +5321,8 @@ }, "node_modules/electron-to-chromium": { "version": "1.5.62", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.62.tgz", - "integrity": "sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", @@ -5504,9 +5420,8 @@ }, "node_modules/enhanced-resolve": { "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -5522,9 +5437,8 @@ }, "node_modules/entities": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -5542,9 +5456,8 @@ }, "node_modules/envinfo": { "version": "7.14.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", - "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", "dev": true, + "license": "MIT", "bin": { "envinfo": "dist/cli.js" }, @@ -5567,9 +5480,8 @@ }, "node_modules/es-abstract": { "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", @@ -5632,9 +5544,8 @@ }, "node_modules/es-define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -5644,9 +5555,8 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -5680,9 +5590,8 @@ }, "node_modules/es-object-atoms": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -5692,9 +5601,8 @@ }, "node_modules/es-set-tostringtag": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4", "has-tostringtag": "^1.0.2", @@ -5706,9 +5614,8 @@ }, "node_modules/es-shim-unscopables": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.0" } @@ -5731,9 +5638,8 @@ }, "node_modules/escalade": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5756,9 +5662,8 @@ }, "node_modules/eslint": { "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -5886,9 +5791,8 @@ }, "node_modules/eslint-module-utils": { "version": "2.12.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", - "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -5903,9 +5807,8 @@ }, "node_modules/eslint-module-utils/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -5979,9 +5882,8 @@ }, "node_modules/eslint-plugin-import": { "version": "2.31.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", - "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, + "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -6507,8 +6409,6 @@ }, "node_modules/fast-uri": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", "dev": true, "funding": [ { @@ -6581,27 +6481,24 @@ }, "node_modules/filelist": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" } }, "node_modules/filelist/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/filelist/node_modules/minimatch": { "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6686,9 +6583,8 @@ }, "node_modules/flat": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } @@ -6923,9 +6819,8 @@ }, "node_modules/get-intrinsic": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -6989,9 +6884,8 @@ }, "node_modules/get-symbol-description": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "es-errors": "^1.3.0", @@ -7301,9 +7195,8 @@ }, "node_modules/has-property-descriptors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -7313,9 +7206,8 @@ }, "node_modules/has-proto": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -7336,9 +7228,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -7356,9 +7247,8 @@ }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -7714,9 +7604,8 @@ }, "node_modules/internal-slot": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.0", @@ -7741,9 +7630,8 @@ }, "node_modules/is-array-buffer": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1" @@ -7841,9 +7729,8 @@ }, "node_modules/is-core-module": { "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -7856,9 +7743,8 @@ }, "node_modules/is-data-view": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, + "license": "MIT", "dependencies": { "is-typed-array": "^1.1.13" }, @@ -7961,9 +7847,8 @@ }, "node_modules/is-negative-zero": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -8051,9 +7936,8 @@ }, "node_modules/is-shared-array-buffer": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7" }, @@ -8124,9 +8008,8 @@ }, "node_modules/is-typed-array": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, + "license": "MIT", "dependencies": { "which-typed-array": "^1.1.14" }, @@ -8269,9 +8152,8 @@ }, "node_modules/jake": { "version": "10.9.1", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.1.tgz", - "integrity": "sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", @@ -9424,9 +9306,8 @@ }, "node_modules/linkify-it": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, + "license": "MIT", "dependencies": { "uc.micro": "^2.0.0" } @@ -9646,9 +9527,8 @@ }, "node_modules/markdown-it": { "version": "14.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", @@ -9663,9 +9543,8 @@ }, "node_modules/mdurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/media-typer": { "version": "0.3.0", @@ -10301,9 +10180,8 @@ }, "node_modules/node-releases": { "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/noms": { "version": "0.0.0", @@ -10718,9 +10596,8 @@ }, "node_modules/object.assign": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "define-properties": "^1.2.1", @@ -10749,9 +10626,8 @@ }, "node_modules/object.fromentries": { "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -10785,9 +10661,8 @@ }, "node_modules/object.groupby": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -10812,9 +10687,8 @@ }, "node_modules/object.values": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -11262,9 +11136,8 @@ }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -11320,9 +11193,8 @@ }, "node_modules/possible-typed-array-names": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -11476,9 +11348,8 @@ }, "node_modules/punycode.js": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -11575,8 +11446,6 @@ }, "node_modules/randombytes": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11607,8 +11476,6 @@ }, "node_modules/react": { "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", - "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", "dev": true, "license": "MIT", "engines": { @@ -11956,9 +11823,8 @@ }, "node_modules/regexp.prototype.flags": { "version": "1.5.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", - "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -12031,8 +11897,6 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, "license": "MIT", "engines": { @@ -12203,9 +12067,8 @@ }, "node_modules/safe-array-concat": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "get-intrinsic": "^1.2.4", @@ -12240,9 +12103,8 @@ }, "node_modules/safe-regex-test": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -12262,8 +12124,6 @@ }, "node_modules/schema-utils": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", - "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", "dev": true, "license": "MIT", "dependencies": { @@ -12282,8 +12142,6 @@ }, "node_modules/schema-utils/node_modules/ajv": { "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { @@ -12299,8 +12157,6 @@ }, "node_modules/schema-utils/node_modules/ajv-keywords": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, "license": "MIT", "dependencies": { @@ -12312,16 +12168,13 @@ }, "node_modules/schema-utils/node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, "node_modules/semver": { "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -12331,8 +12184,6 @@ }, "node_modules/serialize-javascript": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -12346,9 +12197,8 @@ }, "node_modules/set-function-length": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -12363,9 +12213,8 @@ }, "node_modules/set-function-name": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -12887,9 +12736,8 @@ }, "node_modules/string.prototype.trim": { "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -12905,9 +12753,8 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -12919,9 +12766,8 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -13105,8 +12951,6 @@ }, "node_modules/terser": { "version": "5.39.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", - "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -13124,8 +12968,6 @@ }, "node_modules/terser-webpack-plugin": { "version": "5.3.12", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.12.tgz", - "integrity": "sha512-jDLYqo7oF8tJIttjXO6jBY5Hk8p3A8W4ttih7cCEq64fQFWmgJ4VqAQjKr7WwIDlmXKEc6QeoRb5ecjZ+2afcg==", "dev": true, "license": "MIT", "dependencies": { @@ -13159,8 +13001,6 @@ }, "node_modules/terser-webpack-plugin/node_modules/jest-worker": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "license": "MIT", "dependencies": { @@ -13174,8 +13014,6 @@ }, "node_modules/terser-webpack-plugin/node_modules/supports-color": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -13333,9 +13171,8 @@ }, "node_modules/ts-jest": { "version": "29.2.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", - "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", "dev": true, + "license": "MIT", "dependencies": { "bs-logger": "^0.2.6", "ejs": "^3.1.10", @@ -13389,8 +13226,6 @@ }, "node_modules/ts-loader": { "version": "9.5.2", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.2.tgz", - "integrity": "sha512-Qo4piXvOTWcMGIgRiuFa6nHNm+54HbYaZCKqc9eeZCLRy3XqafQgwX2F7mofrbJG3g7EEb+lkiR+z2Lic2s3Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -13567,9 +13402,8 @@ }, "node_modules/typed-array-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -13581,9 +13415,8 @@ }, "node_modules/typed-array-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -13600,9 +13433,8 @@ }, "node_modules/typed-array-byte-offset": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -13620,9 +13452,8 @@ }, "node_modules/typed-array-length": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -13653,8 +13484,6 @@ }, "node_modules/typedoc": { "version": "0.27.9", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.27.9.tgz", - "integrity": "sha512-/z585740YHURLl9DN2jCWe6OW7zKYm6VoQ93H0sxZ1cwHQEQrUn5BJrEnkWhfzUdyO+BLGjnKUZ9iz9hKloFDw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -13676,18 +13505,16 @@ }, "node_modules/typedoc/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/typedoc/node_modules/minimatch": { "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -13700,9 +13527,8 @@ }, "node_modules/typedoc/node_modules/yaml": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", "dev": true, + "license": "ISC", "bin": { "yaml": "bin.mjs" }, @@ -13742,9 +13568,8 @@ }, "node_modules/uc.micro": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/uglify-js": { "version": "3.17.4", @@ -13787,9 +13612,8 @@ }, "node_modules/undici-types": { "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/unique-filename": { "version": "1.1.1", @@ -13847,8 +13671,6 @@ }, "node_modules/update-browserslist-db": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -13864,6 +13686,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.0" @@ -14014,8 +13837,6 @@ }, "node_modules/webpack": { "version": "5.98.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", - "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", "dev": true, "license": "MIT", "dependencies": { @@ -14114,9 +13935,8 @@ }, "node_modules/webpack-cli": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", - "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "dev": true, + "license": "MIT", "dependencies": { "@discoveryjs/json-ext": "^0.6.1", "@webpack-cli/configtest": "^3.0.1", @@ -14156,27 +13976,24 @@ }, "node_modules/webpack-cli/node_modules/@discoveryjs/json-ext": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", - "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.17.0" } }, "node_modules/webpack-cli/node_modules/commander": { "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/webpack-merge": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", - "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "dev": true, + "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", @@ -14279,9 +14096,8 @@ }, "node_modules/which-typed-array": { "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -14306,9 +14122,8 @@ }, "node_modules/wildcard": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wordwrap": { "version": "1.0.0", @@ -14504,8 +14319,6 @@ }, "node_modules/ws": { "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -14664,6 +14477,9 @@ "packages/xrpl": { "version": "4.2.0-batch.0", "license": "ISC", + "dependencies": { + "@scure/bip32": "^1.3.1", + "@scure/bip39": "^1.2.1", "@xrplf/isomorphic": "^1.0.1", "@xrplf/secret-numbers": "^1.0.0", "bignumber.js": "^9.0.0", @@ -14691,22 +14507,21 @@ } }, "packages/xrpl/node_modules/agent-base": { - "version": "7.1.0", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, "engines": { "node": ">= 14" } }, "packages/xrpl/node_modules/https-proxy-agent": { - "version": "7.0.1", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, - "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { From 0e49ebfbf212165c57119c20241ea901e445bab6 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Apr 2025 16:48:52 -0400 Subject: [PATCH 59/73] back out unrelated changes --- package-lock.json | 487 ++++++++++++++------- packages/ripple-address-codec/package.json | 2 +- 2 files changed, 336 insertions(+), 153 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a2dddb3a1..f261c848ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -787,8 +787,9 @@ }, "node_modules/@eslint/js": { "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, - "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -800,8 +801,9 @@ }, "node_modules/@gerrit0/mini-shiki": { "version": "1.24.4", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-1.24.4.tgz", + "integrity": "sha512-YEHW1QeAg6UmxEmswiQbOVEg1CW22b1XUD/lNTliOsu0LD0wqoyleFMnmbTp697QE0pcadQiR5cVtbbAPncvpw==", "dev": true, - "license": "MIT", "dependencies": { "@shikijs/engine-oniguruma": "^1.24.2", "@shikijs/types": "^1.24.2", @@ -810,8 +812,10 @@ }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, - "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -835,8 +839,10 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "2.0.3", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true }, "node_modules/@hutson/parse-repository-url": { "version": "3.0.2", @@ -1226,6 +1232,8 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, "license": "MIT", "dependencies": { @@ -1247,6 +1255,8 @@ }, "node_modules/@jridgewell/set-array": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "license": "MIT", "engines": { @@ -1255,6 +1265,8 @@ }, "node_modules/@jridgewell/source-map": { "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1269,6 +1281,8 @@ }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2286,6 +2300,8 @@ }, "node_modules/@noble/curves": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", + "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", "license": "MIT", "dependencies": { "@noble/hashes": "1.7.1" @@ -2299,6 +2315,8 @@ }, "node_modules/@noble/hashes": { "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -2604,11 +2622,14 @@ }, "node_modules/@rtsao/scc": { "version": "1.1.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true }, "node_modules/@scure/base": { "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.4.tgz", + "integrity": "sha512-5Yy9czTO47mqz+/J8GM6GIId4umdCk1wc1q8rKERQulIoc8VP9pzDcghv10Tl2E7R96ZUx/PhND3ESYUQX8NuQ==", "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" @@ -2616,6 +2637,8 @@ }, "node_modules/@scure/bip32": { "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", + "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", "license": "MIT", "dependencies": { "@noble/curves": "~1.8.1", @@ -2628,6 +2651,8 @@ }, "node_modules/@scure/bip39": { "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", + "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", "license": "MIT", "dependencies": { "@noble/hashes": "~1.7.1", @@ -2639,8 +2664,9 @@ }, "node_modules/@shikijs/engine-oniguruma": { "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.25.1.tgz", + "integrity": "sha512-iKPMh3H+0USHtWfZ1irfMTH6tGmIUFSnqt3E2K8BgI1VEsqiPh0RYkG2WTwzNiM1/WHN4FzYx/nrKR7PDHiRyw==", "dev": true, - "license": "MIT", "dependencies": { "@shikijs/types": "1.25.1", "@shikijs/vscode-textmate": "^9.3.1" @@ -2648,8 +2674,9 @@ }, "node_modules/@shikijs/types": { "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.25.1.tgz", + "integrity": "sha512-dceqFUoO95eY4tpOj3OGq8wE8EgJ4ey6Me1HQEu5UbwIYszFndEll/bjlB8Kp9wl4fx3uM7n4+y9XCYuDBmcXA==", "dev": true, - "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^9.3.1", "@types/hast": "^3.0.4" @@ -2657,8 +2684,9 @@ }, "node_modules/@shikijs/vscode-textmate": { "version": "9.3.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.3.1.tgz", + "integrity": "sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g==", + "dev": true }, "node_modules/@sinclair/typebox": { "version": "0.27.8", @@ -2771,8 +2799,9 @@ }, "node_modules/@types/eslint": { "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -2780,8 +2809,9 @@ }, "node_modules/@types/eslint-scope": { "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, - "license": "MIT", "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -2789,8 +2819,9 @@ }, "node_modules/@types/estree": { "version": "1.0.6", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true }, "node_modules/@types/graceful-fs": { "version": "4.1.7", @@ -2802,8 +2833,9 @@ }, "node_modules/@types/hast": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "*" } @@ -2831,8 +2863,9 @@ }, "node_modules/@types/jest": { "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", "dev": true, - "license": "MIT", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -2850,6 +2883,8 @@ }, "node_modules/@types/lodash": { "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==", "dev": true, "license": "MIT" }, @@ -2865,8 +2900,9 @@ }, "node_modules/@types/node": { "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", "dev": true, - "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } @@ -2893,8 +2929,9 @@ }, "node_modules/@types/unist": { "version": "3.0.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true }, "node_modules/@types/ws": { "version": "8.18.0", @@ -3106,8 +3143,9 @@ }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, - "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" @@ -3115,23 +3153,27 @@ }, "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.13.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, - "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", @@ -3140,13 +3182,15 @@ }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.13.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, - "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -3156,29 +3200,33 @@ }, "node_modules/@webassemblyjs/ieee754": { "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, - "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { "version": "1.13.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, - "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -3192,8 +3240,9 @@ }, "node_modules/@webassemblyjs/wasm-gen": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, - "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", @@ -3204,8 +3253,9 @@ }, "node_modules/@webassemblyjs/wasm-opt": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, - "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -3215,8 +3265,9 @@ }, "node_modules/@webassemblyjs/wasm-parser": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, - "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", @@ -3228,8 +3279,9 @@ }, "node_modules/@webassemblyjs/wast-printer": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, - "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" @@ -3237,8 +3289,9 @@ }, "node_modules/@webpack-cli/configtest": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", + "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18.12.0" }, @@ -3249,8 +3302,9 @@ }, "node_modules/@webpack-cli/info": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", + "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=18.12.0" }, @@ -3261,8 +3315,9 @@ }, "node_modules/@webpack-cli/serve": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", + "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", "dev": true, - "license": "MIT", "engines": { "node": ">=18.12.0" }, @@ -3315,13 +3370,15 @@ }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true }, "node_modules/@xtuc/long": { "version": "4.2.2", - "dev": true, - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true }, "node_modules/abbrev": { "version": "1.1.1", @@ -3342,8 +3399,9 @@ }, "node_modules/acorn": { "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3423,6 +3481,8 @@ }, "node_modules/ajv-formats": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, "license": "MIT", "dependencies": { @@ -3439,6 +3499,8 @@ }, "node_modules/ajv-formats/node_modules/ajv": { "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { @@ -3454,6 +3516,8 @@ }, "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, @@ -3583,8 +3647,9 @@ }, "node_modules/array-buffer-byte-length": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "is-array-buffer": "^3.0.4" @@ -3611,8 +3676,9 @@ }, "node_modules/array-includes": { "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -3638,8 +3704,9 @@ }, "node_modules/array.prototype.findlastindex": { "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -3722,8 +3789,9 @@ }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, - "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.5", @@ -3786,8 +3854,9 @@ }, "node_modules/async": { "version": "3.2.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true }, "node_modules/asynciterator.prototype": { "version": "1.0.0", @@ -3813,8 +3882,9 @@ }, "node_modules/available-typed-arrays": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, - "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -4068,6 +4138,8 @@ }, "node_modules/browserslist": { "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, "funding": [ { @@ -4083,7 +4155,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001669", "electron-to-chromium": "^1.5.41", @@ -4196,8 +4267,9 @@ }, "node_modules/call-bind": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, - "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -4277,6 +4349,8 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001680", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", + "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", "dev": true, "funding": [ { @@ -4291,8 +4365,7 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/caseless": { "version": "0.12.0", @@ -4575,6 +4648,8 @@ }, "node_modules/commander": { "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, "license": "MIT" }, @@ -4964,8 +5039,9 @@ }, "node_modules/data-view-buffer": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -4980,8 +5056,9 @@ }, "node_modules/data-view-byte-length": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -4996,8 +5073,9 @@ }, "node_modules/data-view-byte-offset": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -5144,8 +5222,9 @@ }, "node_modules/define-data-property": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, - "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -5160,8 +5239,9 @@ }, "node_modules/define-properties": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, - "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -5347,8 +5427,9 @@ }, "node_modules/ejs": { "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" }, @@ -5361,8 +5442,9 @@ }, "node_modules/electron-to-chromium": { "version": "1.5.62", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.62.tgz", + "integrity": "sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg==", + "dev": true }, "node_modules/emittery": { "version": "0.13.1", @@ -5460,8 +5542,9 @@ }, "node_modules/enhanced-resolve": { "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, - "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -5477,8 +5560,9 @@ }, "node_modules/entities": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -5496,8 +5580,9 @@ }, "node_modules/envinfo": { "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", "dev": true, - "license": "MIT", "bin": { "envinfo": "dist/cli.js" }, @@ -5520,8 +5605,9 @@ }, "node_modules/es-abstract": { "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, - "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", @@ -5594,8 +5680,9 @@ }, "node_modules/es-errors": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" } @@ -5642,8 +5729,9 @@ }, "node_modules/es-set-tostringtag": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, - "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4", "has-tostringtag": "^1.0.2", @@ -5655,8 +5743,9 @@ }, "node_modules/es-shim-unscopables": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, - "license": "MIT", "dependencies": { "hasown": "^2.0.0" } @@ -5679,8 +5768,9 @@ }, "node_modules/escalade": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -5703,8 +5793,9 @@ }, "node_modules/eslint": { "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -5832,8 +5923,9 @@ }, "node_modules/eslint-module-utils": { "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -5848,8 +5940,9 @@ }, "node_modules/eslint-module-utils/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -5923,8 +6016,9 @@ }, "node_modules/eslint-plugin-import": { "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, - "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -6450,6 +6544,8 @@ }, "node_modules/fast-uri": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", "dev": true, "funding": [ { @@ -6522,24 +6618,27 @@ }, "node_modules/filelist": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, - "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" } }, "node_modules/filelist/node_modules/brace-expansion": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/filelist/node_modules/minimatch": { "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6626,8 +6725,9 @@ }, "node_modules/flat": { "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, - "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } @@ -6948,8 +7048,9 @@ }, "node_modules/get-symbol-description": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "es-errors": "^1.3.0", @@ -7261,8 +7362,9 @@ }, "node_modules/has-property-descriptors": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, - "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -7272,8 +7374,9 @@ }, "node_modules/has-proto": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -7296,8 +7399,9 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, - "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -7315,8 +7419,9 @@ }, "node_modules/hasown": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, - "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -7672,8 +7777,9 @@ }, "node_modules/internal-slot": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, - "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.0", @@ -7698,8 +7804,9 @@ }, "node_modules/is-array-buffer": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1" @@ -7797,8 +7904,9 @@ }, "node_modules/is-core-module": { "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, - "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -7811,8 +7919,9 @@ }, "node_modules/is-data-view": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, - "license": "MIT", "dependencies": { "is-typed-array": "^1.1.13" }, @@ -7915,8 +8024,9 @@ }, "node_modules/is-negative-zero": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -8006,8 +8116,9 @@ }, "node_modules/is-shared-array-buffer": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7" }, @@ -8078,8 +8189,9 @@ }, "node_modules/is-typed-array": { "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, - "license": "MIT", "dependencies": { "which-typed-array": "^1.1.14" }, @@ -8222,8 +8334,9 @@ }, "node_modules/jake": { "version": "10.9.1", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.1.tgz", + "integrity": "sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", @@ -9376,8 +9489,9 @@ }, "node_modules/linkify-it": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, - "license": "MIT", "dependencies": { "uc.micro": "^2.0.0" } @@ -9597,8 +9711,9 @@ }, "node_modules/markdown-it": { "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", @@ -9623,8 +9738,9 @@ }, "node_modules/mdurl": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true }, "node_modules/media-typer": { "version": "0.3.0", @@ -10262,8 +10378,9 @@ }, "node_modules/node-releases": { "version": "2.0.18", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true }, "node_modules/noms": { "version": "0.0.0", @@ -10685,8 +10802,9 @@ }, "node_modules/object.assign": { "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "define-properties": "^1.2.1", @@ -10715,8 +10833,9 @@ }, "node_modules/object.fromentries": { "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -10750,8 +10869,9 @@ }, "node_modules/object.groupby": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -10776,8 +10896,9 @@ }, "node_modules/object.values": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -11225,8 +11346,9 @@ }, "node_modules/picocolors": { "version": "1.1.1", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", @@ -11282,8 +11404,9 @@ }, "node_modules/possible-typed-array-names": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" } @@ -11437,8 +11560,9 @@ }, "node_modules/punycode.js": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -11537,6 +11661,8 @@ }, "node_modules/randombytes": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11567,6 +11693,8 @@ }, "node_modules/react": { "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", "dev": true, "license": "MIT", "engines": { @@ -11914,8 +12042,9 @@ }, "node_modules/regexp.prototype.flags": { "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -11988,6 +12117,8 @@ }, "node_modules/require-from-string": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, "license": "MIT", "engines": { @@ -12158,8 +12289,9 @@ }, "node_modules/safe-array-concat": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "get-intrinsic": "^1.2.4", @@ -12194,8 +12326,9 @@ }, "node_modules/safe-regex-test": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -12215,6 +12348,8 @@ }, "node_modules/schema-utils": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", + "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", "dev": true, "license": "MIT", "dependencies": { @@ -12233,6 +12368,8 @@ }, "node_modules/schema-utils/node_modules/ajv": { "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { @@ -12248,6 +12385,8 @@ }, "node_modules/schema-utils/node_modules/ajv-keywords": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, "license": "MIT", "dependencies": { @@ -12259,13 +12398,16 @@ }, "node_modules/schema-utils/node_modules/json-schema-traverse": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, "node_modules/semver": { "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -12275,6 +12417,8 @@ }, "node_modules/serialize-javascript": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -12288,8 +12432,9 @@ }, "node_modules/set-function-length": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, - "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -12304,8 +12449,9 @@ }, "node_modules/set-function-name": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, - "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -12890,8 +13036,9 @@ }, "node_modules/string.prototype.trim": { "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -12907,8 +13054,9 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -12920,8 +13068,9 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -13107,6 +13256,8 @@ }, "node_modules/terser": { "version": "5.39.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", + "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -13124,6 +13275,8 @@ }, "node_modules/terser-webpack-plugin": { "version": "5.3.12", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.12.tgz", + "integrity": "sha512-jDLYqo7oF8tJIttjXO6jBY5Hk8p3A8W4ttih7cCEq64fQFWmgJ4VqAQjKr7WwIDlmXKEc6QeoRb5ecjZ+2afcg==", "dev": true, "license": "MIT", "dependencies": { @@ -13157,6 +13310,8 @@ }, "node_modules/terser-webpack-plugin/node_modules/jest-worker": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "license": "MIT", "dependencies": { @@ -13170,6 +13325,8 @@ }, "node_modules/terser-webpack-plugin/node_modules/supports-color": { "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -13329,8 +13486,9 @@ }, "node_modules/ts-jest": { "version": "29.2.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", + "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", "dev": true, - "license": "MIT", "dependencies": { "bs-logger": "^0.2.6", "ejs": "^3.1.10", @@ -13384,6 +13542,8 @@ }, "node_modules/ts-loader": { "version": "9.5.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.2.tgz", + "integrity": "sha512-Qo4piXvOTWcMGIgRiuFa6nHNm+54HbYaZCKqc9eeZCLRy3XqafQgwX2F7mofrbJG3g7EEb+lkiR+z2Lic2s3Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -13560,8 +13720,9 @@ }, "node_modules/typed-array-buffer": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -13573,8 +13734,9 @@ }, "node_modules/typed-array-byte-length": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -13591,8 +13753,9 @@ }, "node_modules/typed-array-byte-offset": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, - "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -13610,8 +13773,9 @@ }, "node_modules/typed-array-length": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -13642,6 +13806,8 @@ }, "node_modules/typedoc": { "version": "0.27.9", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.27.9.tgz", + "integrity": "sha512-/z585740YHURLl9DN2jCWe6OW7zKYm6VoQ93H0sxZ1cwHQEQrUn5BJrEnkWhfzUdyO+BLGjnKUZ9iz9hKloFDw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -13663,16 +13829,18 @@ }, "node_modules/typedoc/node_modules/brace-expansion": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/typedoc/node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -13685,8 +13853,9 @@ }, "node_modules/typedoc/node_modules/yaml": { "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", "dev": true, - "license": "ISC", "bin": { "yaml": "bin.mjs" }, @@ -13726,8 +13895,9 @@ }, "node_modules/uc.micro": { "version": "2.1.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true }, "node_modules/uglify-js": { "version": "3.17.4", @@ -13770,8 +13940,9 @@ }, "node_modules/undici-types": { "version": "5.26.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true }, "node_modules/unique-filename": { "version": "1.1.1", @@ -13829,6 +14000,8 @@ }, "node_modules/update-browserslist-db": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -13844,7 +14017,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.0" @@ -13995,6 +14167,8 @@ }, "node_modules/webpack": { "version": "5.98.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", + "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", "dev": true, "license": "MIT", "dependencies": { @@ -14095,8 +14269,9 @@ }, "node_modules/webpack-cli": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", + "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "dev": true, - "license": "MIT", "dependencies": { "@discoveryjs/json-ext": "^0.6.1", "@webpack-cli/configtest": "^3.0.1", @@ -14136,24 +14311,27 @@ }, "node_modules/webpack-cli/node_modules/@discoveryjs/json-ext": { "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", + "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.17.0" } }, "node_modules/webpack-cli/node_modules/commander": { "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/webpack-merge": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "dev": true, - "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", @@ -14256,8 +14434,9 @@ }, "node_modules/which-typed-array": { "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, - "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -14282,8 +14461,9 @@ }, "node_modules/wildcard": { "version": "2.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true }, "node_modules/wordwrap": { "version": "1.0.0", @@ -14479,6 +14659,8 @@ }, "node_modules/ws": { "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -14595,14 +14777,14 @@ "license": "ISC", "dependencies": { "@scure/base": "^1.1.3", - "@xrplf/isomorphic": "^1.0.1" + "@xrplf/isomorphic": "^1.0.0" }, "engines": { "node": ">= 18" } }, "packages/ripple-binary-codec": { - "version": "2.3.0-batch.0", + "version": "2.3.0", "license": "ISC", "dependencies": { "@xrplf/isomorphic": "^1.0.1", @@ -14618,7 +14800,7 @@ "license": "ISC", "dependencies": { "@noble/curves": "^1.0.0", - "@xrplf/isomorphic": "^1.0.1", + "@xrplf/isomorphic": "^1.0.0", "ripple-address-codec": "^5.0.0" }, "engines": { @@ -14630,12 +14812,12 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@xrplf/isomorphic": "^1.0.1", + "@xrplf/isomorphic": "^1.0.0", "ripple-keypairs": "^2.0.0" } }, "packages/xrpl": { - "version": "4.2.0-batch.0", + "version": "4.2.0", "license": "ISC", "dependencies": { "@scure/bip32": "^1.3.1", @@ -14645,7 +14827,7 @@ "bignumber.js": "^9.0.0", "eventemitter3": "^5.0.1", "ripple-address-codec": "^5.0.0", - "ripple-binary-codec": "^2.3.0-batch.0", + "ripple-binary-codec": "^2.3.0", "ripple-keypairs": "^2.0.0" }, "devDependencies": { @@ -14667,21 +14849,22 @@ } }, "packages/xrpl/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "version": "7.1.0", "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, "engines": { "node": ">= 14" } }, "packages/xrpl/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "version": "7.0.1", "dev": true, + "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", + "agent-base": "^7.0.2", "debug": "4" }, "engines": { diff --git a/packages/ripple-address-codec/package.json b/packages/ripple-address-codec/package.json index 9fa164b9f0..bd791c797a 100644 --- a/packages/ripple-address-codec/package.json +++ b/packages/ripple-address-codec/package.json @@ -11,7 +11,7 @@ "license": "ISC", "dependencies": { "@scure/base": "^1.1.3", - "@xrplf/isomorphic": "^1.0.1" + "@xrplf/isomorphic": "^1.0.0" }, "keywords": [ "ripple", From f9afbfdba90750f385964d37167db1a71d4019b8 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 1 Apr 2025 16:51:05 -0400 Subject: [PATCH 60/73] more backing out --- packages/ripple-keypairs/package.json | 2 +- packages/secret-numbers/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ripple-keypairs/package.json b/packages/ripple-keypairs/package.json index 62de4afbcb..b5899b1f50 100644 --- a/packages/ripple-keypairs/package.json +++ b/packages/ripple-keypairs/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@noble/curves": "^1.0.0", - "@xrplf/isomorphic": "^1.0.1", + "@xrplf/isomorphic": "^1.0.0", "ripple-address-codec": "^5.0.0" }, "keywords": [ diff --git a/packages/secret-numbers/package.json b/packages/secret-numbers/package.json index facb8a5270..4eb6c0cfd6 100644 --- a/packages/secret-numbers/package.json +++ b/packages/secret-numbers/package.json @@ -29,7 +29,7 @@ "test": "test" }, "dependencies": { - "@xrplf/isomorphic": "^1.0.1", + "@xrplf/isomorphic": "^1.0.0", "ripple-keypairs": "^2.0.0" }, "prettier": "@xrplf/prettier-config", From 027861e351ba592d07919d3c2bc7476c2286aafa Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 10 Apr 2025 14:17:50 -0400 Subject: [PATCH 61/73] rename test file --- packages/xrpl/test/models/{Batch.test.ts => batch.test.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/xrpl/test/models/{Batch.test.ts => batch.test.ts} (100%) diff --git a/packages/xrpl/test/models/Batch.test.ts b/packages/xrpl/test/models/batch.test.ts similarity index 100% rename from packages/xrpl/test/models/Batch.test.ts rename to packages/xrpl/test/models/batch.test.ts From 30218224d1558f4bf0c4cd298de16e5fdac2b3e4 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 10 Apr 2025 14:27:40 -0400 Subject: [PATCH 62/73] update tfInnerBatchTxn handling --- .../xrpl/src/models/transactions/batch.ts | 22 ++++++++++++++++++- packages/xrpl/src/sugar/autofill.ts | 20 +++-------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index 6448e5a0e8..19c34726da 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -3,6 +3,7 @@ import { Signer } from '../common' import { BaseTransaction, + GlobalFlags, GlobalFlagsInterface, isArray, isObject, @@ -108,8 +109,27 @@ export function validateBatch(tx: Record): void { `Batch: RawTransactions[${index}] is a Batch transaction. Cannot nest Batch transactions.`, ) } + + // Automatically add the `tfInnerBatchTxn` flag to the inner transactions + /* eslint-disable no-bitwise -- needed here for flag parsing */ + if (rawTx.Flags == null) { + rawTx.Flags = GlobalFlags.tfInnerBatchTxn + } else if (typeof rawTx.Flags === 'number') { + if (!((rawTx.Flags & GlobalFlags.tfInnerBatchTxn) === 0)) { + rawTx.Flags |= GlobalFlags.tfInnerBatchTxn + } + } else if (typeof rawTx.Flags === 'object') { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above + const flags = rawTx.Flags as Record + if (!flags.tfInnerBatchTxn) { + // txInnerBatchTxn is either false or null + flags.tfInnerBatchTxn = true + } + } + /* eslint-enable no-bitwise */ + + // Full validation of each `RawTransaction` object is done in `validate` to avoid dependency cycles }) - // Full validation of each `RawTransaction` object is done in `validate` to avoid dependency cycles validateOptionalField(tx, 'BatchSigners', isArray) diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 3352a74da5..a7661ea990 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -6,7 +6,6 @@ import { type Client } from '..' import { ValidationError, XrplError } from '../errors' import { AccountInfoRequest, AccountObjectsRequest } from '../models/methods' import { Batch, Payment, Transaction } from '../models/transactions' -import { GlobalFlags } from '../models/transactions/common' import { xrpToDrops } from '../utils' import getFeeXrp from './getFeeXrp' @@ -415,7 +414,7 @@ export function handleDeliverMax(tx: Payment): void { * @param tx - The transaction object. * @returns A promise that resolves with void if there are no blockers, or rejects with an XrplError if there are blockers. */ -// eslint-disable-next-line complexity, max-lines-per-function, max-statements -- needed here, lots to check +// eslint-disable-next-line complexity, max-lines-per-function -- needed here, lots to check export async function autofillBatchTxn( client: Client, tx: Batch, @@ -425,19 +424,6 @@ export async function autofillBatchTxn( for await (const rawTxn of tx.RawTransactions) { const txn = rawTxn.RawTransaction - // Flag processing - /* eslint-disable no-bitwise -- needed here for flag parsing */ - if (txn.Flags == null) { - txn.Flags = GlobalFlags.tfInnerBatchTxn - } else if (typeof txn.Flags === 'number') { - if (!((txn.Flags & GlobalFlags.tfInnerBatchTxn) === 0)) { - txn.Flags |= GlobalFlags.tfInnerBatchTxn - } - } else if (!txn.Flags.tfInnerBatchTxn) { - txn.Flags.tfInnerBatchTxn = true - } - /* eslint-enable no-bitwise */ - // Sequence processing if (txn.Sequence == null && txn.TicketSequence == null) { if (txn.Account in accountSequences) { @@ -457,14 +443,14 @@ export async function autofillBatchTxn( if (txn.Fee == null) { txn.Fee = '0' - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JS check + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS } else if (txn.Fee !== '0') { throw new XrplError('Must have `Fee of "0" in inner Batch transaction.') } if (txn.SigningPubKey == null) { txn.SigningPubKey = '' - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JS check + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS } else if (txn.SigningPubKey !== '') { throw new XrplError( 'Must have `SigningPubKey` of "" in inner Batch transaction.', From 9a54bec24390d6f7fe057a87fd74471fe6379b5a Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 16 Apr 2025 11:09:50 -0400 Subject: [PATCH 63/73] respond to comments --- packages/ripple-binary-codec/src/index.ts | 12 ++++++++++-- packages/xrpl/test/client/autofill.test.ts | 17 ++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/ripple-binary-codec/src/index.ts b/packages/ripple-binary-codec/src/index.ts index 4ee74396c0..2ba85f2a82 100644 --- a/packages/ripple-binary-codec/src/index.ts +++ b/packages/ripple-binary-codec/src/index.ts @@ -72,7 +72,7 @@ function encodeForSigning( } /** - * Encode a transaction and prepare for signing with a claim + * Encode a payment channel claim for signing. * * @param json JSON object representing the transaction * @param signer string representing the account to sign the transaction with @@ -111,9 +111,17 @@ function encodeForMultisigning( ) } +/** + * Encode a Batch transaction for signing. + * + * @param json JSON object representing the transaction + * @param signer string representing the account to sign the transaction with + * @param definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. + * @returns a hex string of the encoded transaction + */ function encodeForSigningBatch(json: object): string { if (typeof json !== 'object') { - throw new Error() + throw new Error('Need an object to encode a Batch transaction') } return bytesToHex(signingBatchData(json as BatchObject)) } diff --git a/packages/xrpl/test/client/autofill.test.ts b/packages/xrpl/test/client/autofill.test.ts index 653c010711..2f1a92b59f 100644 --- a/packages/xrpl/test/client/autofill.test.ts +++ b/packages/xrpl/test/client/autofill.test.ts @@ -438,15 +438,16 @@ describe('client.autofill', function () { }) it('should autofill Batch transaction with single account', async function () { + const sender = 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf' const tx: Batch = { TransactionType: 'Batch', - Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + Account: sender, RawTransactions: [ { RawTransaction: { TransactionType: 'DepositPreauth', Flags: 0x40000000, - Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + Account: sender, Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', }, }, @@ -454,7 +455,7 @@ describe('client.autofill', function () { RawTransaction: { TransactionType: 'DepositPreauth', Flags: 0x40000000, - Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + Account: sender, Authorize: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', }, }, @@ -479,16 +480,18 @@ describe('client.autofill', function () { }) }) - it('should autofill Batch transaction with single account', async function () { + it('should autofill Batch transaction with multiple accounts', async function () { + const sender1 = 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf' + const sender2 = 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn' const tx: Transaction = { TransactionType: 'Batch', - Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + Account: sender1, RawTransactions: [ { RawTransaction: { TransactionType: 'DepositPreauth', Flags: 0x40000000, - Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', + Account: sender1, Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', }, }, @@ -496,7 +499,7 @@ describe('client.autofill', function () { RawTransaction: { TransactionType: 'DepositPreauth', Flags: 0x40000000, - Account: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn', + Account: sender2, Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', }, }, From b8db856edc7e0cb0f4d6410a8a79e272d78945f7 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 16 Apr 2025 11:28:24 -0400 Subject: [PATCH 64/73] fix coderabbit issues --- packages/ripple-binary-codec/src/binary.ts | 8 +++++-- packages/ripple-binary-codec/src/index.ts | 20 +++++++--------- packages/xrpl/HISTORY.md | 2 +- .../xrpl/src/models/transactions/common.ts | 4 ++-- .../xrpl/test/wallet/authorizeChannel.test.ts | 24 +++++++++++++++++-- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/packages/ripple-binary-codec/src/binary.ts b/packages/ripple-binary-codec/src/binary.ts index 29dc1589e9..420d2bc138 100644 --- a/packages/ripple-binary-codec/src/binary.ts +++ b/packages/ripple-binary-codec/src/binary.ts @@ -179,6 +179,8 @@ function multiSigningData( /** * Interface describing fields required for a Batch signer + * @property flags - Flags indicating Batch transaction properties + * @property txIDs - Array of transaction IDs included in the Batch */ interface BatchObject extends JsonObject { flags: number @@ -188,8 +190,7 @@ interface BatchObject extends JsonObject { /** * Serialize a signingClaim * - * @param batch A Batch object to serialize - * @param opts.definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. + * @param batch A Batch object to serialize. * @returns the serialized object with appropriate prefix */ function signingBatchData(batch: BatchObject): Uint8Array { @@ -209,6 +210,9 @@ function signingBatchData(batch: BatchObject): Uint8Array { bytesList.put(flags) bytesList.put(txIDsLength) batch.txIDs.forEach((txID: string) => { + if (!/^[A-F0-9]{64}$/i.test(txID)) { + throw new Error(`Invalid transaction ID format: ${txID}`) + } bytesList.put(coreTypes.Hash256.from(txID).toBytes()) }) diff --git a/packages/ripple-binary-codec/src/index.ts b/packages/ripple-binary-codec/src/index.ts index 2ba85f2a82..72dcb4bad3 100644 --- a/packages/ripple-binary-codec/src/index.ts +++ b/packages/ripple-binary-codec/src/index.ts @@ -74,10 +74,8 @@ function encodeForSigning( /** * Encode a payment channel claim for signing. * - * @param json JSON object representing the transaction - * @param signer string representing the account to sign the transaction with - * @param definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. - * @returns a hex string of the encoded transaction + * @param json JSON object representing the claim. + * @returns a hex string of the encoded claim. */ function encodeForSigningClaim(json: object): string { if (typeof json !== 'object') { @@ -87,12 +85,12 @@ function encodeForSigningClaim(json: object): string { } /** - * Encode a transaction and prepare for multi-signing + * Encode a transaction and prepare for multi-signing. * - * @param json JSON object representing the transaction - * @param signer string representing the account to sign the transaction with + * @param json JSON object representing the transaction. + * @param signer string representing the account to sign the transaction with. * @param definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. - * @returns a hex string of the encoded transaction + * @returns a hex string of the encoded transaction. */ function encodeForMultisigning( json: object, @@ -114,10 +112,8 @@ function encodeForMultisigning( /** * Encode a Batch transaction for signing. * - * @param json JSON object representing the transaction - * @param signer string representing the account to sign the transaction with - * @param definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. - * @returns a hex string of the encoded transaction + * @param json JSON object representing the transaction. + * @returns a hex string of the encoded transaction. */ function encodeForSigningBatch(json: object): string { if (typeof json !== 'object') { diff --git a/packages/xrpl/HISTORY.md b/packages/xrpl/HISTORY.md index 5974793aa4..ce9133bbba 100644 --- a/packages/xrpl/HISTORY.md +++ b/packages/xrpl/HISTORY.md @@ -6,6 +6,7 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr ### Added * Support for `NFTokenMintOffer` (XLS-52) +* Add support for `Batch` amendment (XLS-56) ### Fixed * `OracleSet` transaction accepts hexadecimal string values for `AssetPrice` field @@ -20,7 +21,6 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr * Support for the Permissioned Domains amendment (XLS-80). * Support for the `simulate` RPC ([XLS-69](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069-simulate)) * Support for XLS-77d Deep-Freeze amendment -* Add support for `Batch` amendment (XLS-56) ### Changed * Deprecated `setTransactionFlagsToNumber`. Start using convertTxFlagsToNumber instead diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index c659662500..6a53f2b3a4 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -217,7 +217,7 @@ export function isXChainBridge(input: unknown): input is XChainBridge { * @returns Whether the Object is properly formed. */ export function isObject(input: unknown): input is object { - return typeof input === 'object' + return input !== null && typeof input === 'object' } /** @@ -226,7 +226,7 @@ export function isObject(input: unknown): input is object { * @param input - The object to check the form and type of. * @returns Whether the Array is properly formed. */ -export function isArray(input: unknown): boolean { +export function isArray(input: unknown): input is T[] { return Array.isArray(input) } diff --git a/packages/xrpl/test/wallet/authorizeChannel.test.ts b/packages/xrpl/test/wallet/authorizeChannel.test.ts index 9681dbe152..e838921f94 100644 --- a/packages/xrpl/test/wallet/authorizeChannel.test.ts +++ b/packages/xrpl/test/wallet/authorizeChannel.test.ts @@ -4,7 +4,7 @@ import { ECDSA, Wallet } from '../../src' import { authorizeChannel } from '../../src/Wallet/authorizeChannel' describe('authorizeChannel', function () { - it('authorizeChannel succeeds with secp256k1 seed', function () { + it('succeeds with secp256k1 seed', function () { const secpWallet = Wallet.fromSeed('snGHNrPbHrdUcszeuDEigMdC1Lyyd', { algorithm: ECDSA.secp256k1, }) @@ -18,7 +18,7 @@ describe('authorizeChannel', function () { ) }) - it('authorizeChannel succeeds with ed25519 seed', function () { + it('succeeds with ed25519 seed', function () { const edWallet = Wallet.fromSeed('sEdSuqBPSQaood2DmNYVkwWTn1oQTj2') const channelId = '5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3' @@ -28,4 +28,24 @@ describe('authorizeChannel', function () { '7E1C217A3E4B3C107B7A356E665088B4FBA6464C48C58267BEF64975E3375EA338AE22E6714E3F5E734AE33E6B97AAD59058E1E196C1F92346FC1498D0674404', ) }) + + it('throws on invalid channel ID format', function () { + const wallet = Wallet.fromSeed('snGHNrPbHrdUcszeuDEigMdC1Lyyd', { + algorithm: ECDSA.secp256k1, + }) + assert.throws(() => { + authorizeChannel(wallet, 'invalid-id', '1000000') + }) + }) + + it('throws on invalid amount format', function () { + const wallet = Wallet.fromSeed('snGHNrPbHrdUcszeuDEigMdC1Lyyd', { + algorithm: ECDSA.secp256k1, + }) + const channelId = + '5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3' + assert.throws(() => { + authorizeChannel(wallet, channelId, 'invalid-amount') + }) + }) }) From 27efb576e167d2028a51174ade0da684238e74cd Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 16 Apr 2025 11:52:47 -0400 Subject: [PATCH 65/73] improve type-checking --- package-lock.json | 6 +- .../xrpl/src/models/transactions/batch.ts | 32 ++++------ .../xrpl/src/models/transactions/common.ts | 62 +++++++++++-------- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/package-lock.json b/package-lock.json index f261c848ff..ea7abdbaa0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14784,7 +14784,7 @@ } }, "packages/ripple-binary-codec": { - "version": "2.3.0", + "version": "2.3.0-batch.0", "license": "ISC", "dependencies": { "@xrplf/isomorphic": "^1.0.1", @@ -14817,7 +14817,7 @@ } }, "packages/xrpl": { - "version": "4.2.0", + "version": "4.2.0-batch.0", "license": "ISC", "dependencies": { "@scure/bip32": "^1.3.1", @@ -14827,7 +14827,7 @@ "bignumber.js": "^9.0.0", "eventemitter3": "^5.0.1", "ripple-address-codec": "^5.0.0", - "ripple-binary-codec": "^2.3.0", + "ripple-binary-codec": "^2.3.0-batch.0", "ripple-keypairs": "^2.0.0" }, "devDependencies": { diff --git a/packages/xrpl/src/models/transactions/batch.ts b/packages/xrpl/src/models/transactions/batch.ts index 19c34726da..5475e59d8b 100644 --- a/packages/xrpl/src/models/transactions/batch.ts +++ b/packages/xrpl/src/models/transactions/batch.ts @@ -6,7 +6,7 @@ import { GlobalFlags, GlobalFlagsInterface, isArray, - isObject, + isRecord, isString, validateBaseTransaction, validateOptionalField, @@ -87,23 +87,19 @@ export function validateBatch(tx: Record): void { validateBaseTransaction(tx) validateRequiredField(tx, 'RawTransactions', isArray) - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const rawTransactions = tx.RawTransactions as unknown[] - rawTransactions.forEach((rawTxObj, index) => { - if (!isObject(rawTxObj)) { + + tx.RawTransactions.forEach((rawTxObj, index) => { + if (!isRecord(rawTxObj)) { throw new ValidationError( `Batch: RawTransactions[${index}] is not object.`, ) } - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const rawTxRecord = rawTxObj as Record - validateRequiredField(rawTxRecord, 'RawTransaction', isObject, { + validateRequiredField(rawTxObj, 'RawTransaction', isRecord, { paramName: `RawTransactions[${index}].RawTransaction`, txType: 'Batch', }) - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const rawTx = rawTxRecord.RawTransaction as Record + const rawTx = rawTxObj.RawTransaction if (rawTx.TransactionType === 'Batch') { throw new ValidationError( `Batch: RawTransactions[${index}] is a Batch transaction. Cannot nest Batch transactions.`, @@ -133,20 +129,18 @@ export function validateBatch(tx: Record): void { validateOptionalField(tx, 'BatchSigners', isArray) - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const batchSigners = tx.BatchSigners as unknown[] | undefined - batchSigners?.forEach((signerObj, index) => { - if (!isObject(signerObj)) { + tx.BatchSigners?.forEach((signerObj, index) => { + if (!isRecord(signerObj)) { throw new ValidationError(`Batch: BatchSigners[${index}] is not object.`) } - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const signerRecord = signerObj as Record - validateRequiredField(signerRecord, 'BatchSigner', isObject, { + + const signerRecord = signerObj + validateRequiredField(signerRecord, 'BatchSigner', isRecord, { paramName: `BatchSigners[${index}].BatchSigner`, txType: 'Batch', }) - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- checked above - const signer = signerRecord.BatchSigner as Record + + const signer = signerRecord.BatchSigner validateRequiredField(signer, 'Account', isString, { paramName: `BatchSigners[${index}].Account`, txType: 'Batch', diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index 6a53f2b3a4..536e125d0a 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -69,7 +69,13 @@ const XCHAIN_BRIDGE_SIZE = 4 const MPTOKEN_SIZE = 2 const AUTHORIZE_CREDENTIAL_SIZE = 1 -function isRecord(value: unknown): value is Record { +/** + * Verify the form and type of a Record/Object at runtime. + * + * @param value - The object to check the form and type of. + * @returns Whether the Record/Object is properly formed. + */ +export function isRecord(value: unknown): value is Record { return value !== null && typeof value === 'object' } @@ -210,16 +216,6 @@ export function isXChainBridge(input: unknown): input is XChainBridge { ) } -/** - * Verify the form and type of an Object at runtime. - * - * @param input - The object to check the form and type of. - * @returns Whether the Object is properly formed. - */ -export function isObject(input: unknown): input is object { - return input !== null && typeof input === 'object' -} - /** * Verify the form and type of an Array at runtime. * @@ -241,26 +237,34 @@ export function isArray(input: unknown): input is T[] { * @param errorOpts - Extra values to make the error message easier to understand. * @param errorOpts.txType - The transaction type throwing the error. * @param errorOpts.paramName - The name of the parameter in the transaction with the error. - * @throws + * @throws ValidationError if the parameter is missing or invalid. */ // eslint-disable-next-line max-params -- helper function -export function validateRequiredField( - tx: Record, - param: string, - checkValidity: (inp: unknown) => boolean, +export function validateRequiredField< + T extends Record, + K extends keyof T, + V, +>( + tx: T, + param: K, + checkValidity: (inp: unknown) => inp is V, errorOpts: { txType?: string paramName?: string } = {}, -): void { +): asserts tx is T & { [P in K]: V } { const paramNameStr = errorOpts.paramName ?? param const txType = errorOpts.txType ?? tx.TransactionType if (tx[param] == null) { - throw new ValidationError(`${txType}: missing field ${paramNameStr}`) + throw new ValidationError( + `${txType}: missing field ${String(paramNameStr)}`, + ) } if (!checkValidity(tx[param])) { - throw new ValidationError(`${txType}: invalid field ${paramNameStr}`) + throw new ValidationError( + `${txType}: invalid field ${String(paramNameStr)}`, + ) } } @@ -273,22 +277,28 @@ export function validateRequiredField( * @param errorOpts - Extra values to make the error message easier to understand. * @param errorOpts.txType - The transaction type throwing the error. * @param errorOpts.paramName - The name of the parameter in the transaction with the error. - * @throws + * @throws ValidationError if the parameter is invalid. */ // eslint-disable-next-line max-params -- helper function -export function validateOptionalField( - tx: Record, - param: string, - checkValidity: (inp: unknown) => boolean, +export function validateOptionalField< + T extends Record, + K extends keyof T, + V, +>( + tx: T, + param: K, + checkValidity: (inp: unknown) => inp is V, errorOpts: { txType?: string paramName?: string } = {}, -): void { +): asserts tx is T & { [P in K]: V | undefined } { const paramNameStr = errorOpts.paramName ?? param const txType = errorOpts.txType ?? tx.TransactionType if (tx[param] !== undefined && !checkValidity(tx[param])) { - throw new ValidationError(`${txType}: invalid field ${paramNameStr}`) + throw new ValidationError( + `${txType}: invalid field ${String(paramNameStr)}`, + ) } } From cffc14113956ab4234990f69b0d97746c6d478d1 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 16 Apr 2025 12:02:14 -0400 Subject: [PATCH 66/73] fix errors --- .../XChainAddAccountCreateAttestation.ts | 4 +- .../transactions/XChainAddClaimAttestation.ts | 4 +- .../src/models/transactions/XChainClaim.ts | 2 +- .../src/models/transactions/XChainCommit.ts | 2 +- .../xrpl/src/models/transactions/common.ts | 6 +- .../xrpl/src/models/transactions/oracleSet.ts | 186 +++++++++--------- .../transactions/permissionedDomainSet.ts | 7 +- 7 files changed, 107 insertions(+), 104 deletions(-) diff --git a/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts b/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts index 16d27035a1..9b4f274e67 100644 --- a/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts +++ b/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts @@ -110,13 +110,13 @@ export function validateXChainAddAccountCreateAttestation( validateRequiredField( tx, 'WasLockingChainSend', - (inp) => inp === 0 || inp === 1, + (inp: unknown): inp is 0 | 1 => inp === 0 || inp === 1, ) validateRequiredField( tx, 'XChainAccountCreateCount', - (inp) => isNumber(inp) || isString(inp), + (inp: unknown): inp is number | string => isNumber(inp) || isString(inp), ) validateRequiredField(tx, 'XChainBridge', isXChainBridge) diff --git a/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts b/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts index 90f09c0bc7..4a1eafe04a 100644 --- a/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts +++ b/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts @@ -104,7 +104,7 @@ export function validateXChainAddClaimAttestation( validateRequiredField( tx, 'WasLockingChainSend', - (inp) => inp === 0 || inp === 1, + (inp: unknown): inp is 0 | 1 => inp === 0 || inp === 1, ) validateRequiredField(tx, 'XChainBridge', isXChainBridge) @@ -112,6 +112,6 @@ export function validateXChainAddClaimAttestation( validateRequiredField( tx, 'XChainClaimID', - (inp) => isNumber(inp) || isString(inp), + (inp: unknown): inp is number | string => isNumber(inp) || isString(inp), ) } diff --git a/packages/xrpl/src/models/transactions/XChainClaim.ts b/packages/xrpl/src/models/transactions/XChainClaim.ts index 124f5f468c..13897e8d5a 100644 --- a/packages/xrpl/src/models/transactions/XChainClaim.ts +++ b/packages/xrpl/src/models/transactions/XChainClaim.ts @@ -68,7 +68,7 @@ export function validateXChainClaim(tx: Record): void { validateRequiredField( tx, 'XChainClaimID', - (inp) => isNumber(inp) || isString(inp), + (inp: unknown): inp is number | string => isNumber(inp) || isString(inp), ) validateRequiredField(tx, 'Destination', isAccount) diff --git a/packages/xrpl/src/models/transactions/XChainCommit.ts b/packages/xrpl/src/models/transactions/XChainCommit.ts index a7434c0fbd..d8767eb27d 100644 --- a/packages/xrpl/src/models/transactions/XChainCommit.ts +++ b/packages/xrpl/src/models/transactions/XChainCommit.ts @@ -67,7 +67,7 @@ export function validateXChainCommit(tx: Record): void { validateRequiredField( tx, 'XChainClaimID', - (inp) => isNumber(inp) || isString(inp), + (inp: unknown): inp is number | string => isNumber(inp) || isString(inp), ) validateOptionalField(tx, 'OtherChainDestination', isAccount) diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index 536e125d0a..c614fa33a3 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -315,7 +315,7 @@ export interface GlobalFlagsInterface { /** * Every transaction has the same set of common fields. */ -export interface BaseTransaction { +export interface BaseTransaction extends Record { /** The unique address of the transaction sender. */ Account: Account /** @@ -396,7 +396,9 @@ export interface BaseTransaction { * @param common - An interface w/ common transaction fields. * @throws When the common param is malformed. */ -export function validateBaseTransaction(common: Record): void { +export function validateBaseTransaction( + common: Record, +): asserts common is BaseTransaction { if (common.TransactionType === undefined) { throw new ValidationError('BaseTransaction: missing field TransactionType') } diff --git a/packages/xrpl/src/models/transactions/oracleSet.ts b/packages/xrpl/src/models/transactions/oracleSet.ts index efd1461561..64c7624ea9 100644 --- a/packages/xrpl/src/models/transactions/oracleSet.ts +++ b/packages/xrpl/src/models/transactions/oracleSet.ts @@ -86,113 +86,117 @@ export function validateOracleSet(tx: Record): void { validateOptionalField(tx, 'AssetClass', isString) /* eslint-disable max-statements, max-lines-per-function -- necessary to validate many fields */ - validateRequiredField(tx, 'PriceDataSeries', (value) => { - if (!Array.isArray(value)) { - throw new ValidationError('OracleSet: PriceDataSeries must be an array') - } - - if (value.length > PRICE_DATA_SERIES_MAX_LENGTH) { - throw new ValidationError( - `OracleSet: PriceDataSeries must have at most ${PRICE_DATA_SERIES_MAX_LENGTH} PriceData objects`, - ) - } - - // TODO: add support for handling inner objects easier (similar to validateRequiredField/validateOptionalField) - for (const priceData of value) { - if (typeof priceData !== 'object') { - throw new ValidationError( - 'OracleSet: PriceDataSeries must be an array of objects', - ) + validateRequiredField( + tx, + 'PriceDataSeries', + (value: unknown): value is PriceData => { + if (!Array.isArray(value)) { + throw new ValidationError('OracleSet: PriceDataSeries must be an array') } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type - if (priceData.PriceData == null) { + if (value.length > PRICE_DATA_SERIES_MAX_LENGTH) { throw new ValidationError( - 'OracleSet: PriceDataSeries must have a `PriceData` object', + `OracleSet: PriceDataSeries must have at most ${PRICE_DATA_SERIES_MAX_LENGTH} PriceData objects`, ) } - // check if priceData only has PriceData - if (Object.keys(priceData).length !== 1) { - throw new ValidationError( - 'OracleSet: PriceDataSeries must only have a single PriceData object', - ) - } + // TODO: add support for handling inner objects easier (similar to validateRequiredField/validateOptionalField) + for (const priceData of value) { + if (typeof priceData !== 'object') { + throw new ValidationError( + 'OracleSet: PriceDataSeries must be an array of objects', + ) + } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type - if (typeof priceData.PriceData.BaseAsset !== 'string') { - throw new ValidationError( - 'OracleSet: PriceDataSeries must have a `BaseAsset` string', - ) - } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type + if (priceData.PriceData == null) { + throw new ValidationError( + 'OracleSet: PriceDataSeries must have a `PriceData` object', + ) + } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type - if (typeof priceData.PriceData.QuoteAsset !== 'string') { - throw new ValidationError( - 'OracleSet: PriceDataSeries must have a `QuoteAsset` string', - ) - } + // check if priceData only has PriceData + if (Object.keys(priceData).length !== 1) { + throw new ValidationError( + 'OracleSet: PriceDataSeries must only have a single PriceData object', + ) + } - // Either AssetPrice and Scale are both present or both excluded - if ( // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type - (priceData.PriceData.AssetPrice == null) !== + if (typeof priceData.PriceData.BaseAsset !== 'string') { + throw new ValidationError( + 'OracleSet: PriceDataSeries must have a `BaseAsset` string', + ) + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type - (priceData.PriceData.Scale == null) - ) { - throw new ValidationError( - 'OracleSet: PriceDataSeries must have both `AssetPrice` and `Scale` if any are present', - ) - } + if (typeof priceData.PriceData.QuoteAsset !== 'string') { + throw new ValidationError( + 'OracleSet: PriceDataSeries must have a `QuoteAsset` string', + ) + } + + // Either AssetPrice and Scale are both present or both excluded + if ( + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type + (priceData.PriceData.AssetPrice == null) !== + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type + (priceData.PriceData.Scale == null) + ) { + throw new ValidationError( + 'OracleSet: PriceDataSeries must have both `AssetPrice` and `Scale` if any are present', + ) + } - /* eslint-disable @typescript-eslint/no-unsafe-member-access, max-depth -- + /* eslint-disable @typescript-eslint/no-unsafe-member-access, max-depth -- we need to validate priceData.PriceData.AssetPrice value */ - if ('AssetPrice' in priceData.PriceData) { - if (!isNumber(priceData.PriceData.AssetPrice)) { - if (typeof priceData.PriceData.AssetPrice !== 'string') { - throw new ValidationError( - 'OracleSet: Field AssetPrice must be a string or a number', - ) - } - if (!isHex(priceData.PriceData.AssetPrice)) { - throw new ValidationError( - 'OracleSet: Field AssetPrice must be a valid hex string', - ) - } - if ( - priceData.PriceData.AssetPrice.length < - MINIMUM_ASSET_PRICE_LENGTH || - priceData.PriceData.AssetPrice.length > MAXIMUM_ASSET_PRICE_LENGTH - ) { - throw new ValidationError( - `OracleSet: Length of AssetPrice field must be between ${MINIMUM_ASSET_PRICE_LENGTH} and ${MAXIMUM_ASSET_PRICE_LENGTH} characters long`, - ) + if ('AssetPrice' in priceData.PriceData) { + if (!isNumber(priceData.PriceData.AssetPrice)) { + if (typeof priceData.PriceData.AssetPrice !== 'string') { + throw new ValidationError( + 'OracleSet: Field AssetPrice must be a string or a number', + ) + } + if (!isHex(priceData.PriceData.AssetPrice)) { + throw new ValidationError( + 'OracleSet: Field AssetPrice must be a valid hex string', + ) + } + if ( + priceData.PriceData.AssetPrice.length < + MINIMUM_ASSET_PRICE_LENGTH || + priceData.PriceData.AssetPrice.length > MAXIMUM_ASSET_PRICE_LENGTH + ) { + throw new ValidationError( + `OracleSet: Length of AssetPrice field must be between ${MINIMUM_ASSET_PRICE_LENGTH} and ${MAXIMUM_ASSET_PRICE_LENGTH} characters long`, + ) + } } } - } - /* eslint-enable @typescript-eslint/no-unsafe-member-access, max-depth */ - - if ( - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type - 'Scale' in priceData.PriceData && - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type - !isNumber(priceData.PriceData.Scale) - ) { - throw new ValidationError('OracleSet: invalid field Scale') - } + /* eslint-enable @typescript-eslint/no-unsafe-member-access, max-depth */ + + if ( + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type + 'Scale' in priceData.PriceData && + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type + !isNumber(priceData.PriceData.Scale) + ) { + throw new ValidationError('OracleSet: invalid field Scale') + } - if ( - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type - priceData.PriceData.Scale < 0 || - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type - priceData.PriceData.Scale > SCALE_MAX - ) { - throw new ValidationError( - `OracleSet: Scale must be in range 0-${SCALE_MAX}`, - ) + if ( + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type + priceData.PriceData.Scale < 0 || + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type + priceData.PriceData.Scale > SCALE_MAX + ) { + throw new ValidationError( + `OracleSet: Scale must be in range 0-${SCALE_MAX}`, + ) + } } - } - return true - }) + return true + }, + ) /* eslint-enable max-statements, max-lines-per-function */ } diff --git a/packages/xrpl/src/models/transactions/permissionedDomainSet.ts b/packages/xrpl/src/models/transactions/permissionedDomainSet.ts index 5e57c0de90..0fedb96a83 100644 --- a/packages/xrpl/src/models/transactions/permissionedDomainSet.ts +++ b/packages/xrpl/src/models/transactions/permissionedDomainSet.ts @@ -7,6 +7,7 @@ import { validateOptionalField, validateRequiredField, validateCredentialsList, + isArray, } from './common' const MAX_ACCEPTED_CREDENTIALS = 10 @@ -36,11 +37,7 @@ export function validatePermissionedDomainSet( validateBaseTransaction(tx) validateOptionalField(tx, 'DomainID', isString) - validateRequiredField( - tx, - 'AcceptedCredentials', - () => tx.AcceptedCredentials instanceof Array, - ) + validateRequiredField(tx, 'AcceptedCredentials', isArray) validateCredentialsList( tx.AcceptedCredentials, From b612edc60f1c6e8f6a840d4ff1b36f075f303c60 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 16 Apr 2025 12:02:14 -0400 Subject: [PATCH 67/73] fix errors --- packages/xrpl/src/client/partialPayment.ts | 7 ++-- .../xrpl/src/models/transactions/AMMBid.ts | 3 +- .../src/models/transactions/accountDelete.ts | 3 +- .../src/models/transactions/depositPreauth.ts | 6 +-- .../src/models/transactions/escrowFinish.ts | 3 +- .../xrpl/src/models/transactions/payment.ts | 10 +++-- .../transactions/paymentChannelClaim.ts | 3 +- .../transactions/permissionedDomainSet.ts | 3 +- .../src/models/transactions/signerListSet.ts | 4 +- packages/xrpl/src/sugar/autofill.ts | 38 ++++++++++--------- 10 files changed, 39 insertions(+), 41 deletions(-) diff --git a/packages/xrpl/src/client/partialPayment.ts b/packages/xrpl/src/client/partialPayment.ts index 8176fb7839..2d91008ef4 100644 --- a/packages/xrpl/src/client/partialPayment.ts +++ b/packages/xrpl/src/client/partialPayment.ts @@ -96,10 +96,9 @@ function isPartialPayment( } const delivered = meta.delivered_amount - // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- DeliverMax is a valid field on Payment response - // @ts-expect-error -- DeliverMax is a valid field on Payment response - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- DeliverMax is a valid field on Payment response - const amount = tx.DeliverMax + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- needed here + const amount = tx.DeliverMax as Amount | MPTAmount if (delivered === undefined) { return false diff --git a/packages/xrpl/src/models/transactions/AMMBid.ts b/packages/xrpl/src/models/transactions/AMMBid.ts index 046aeacceb..dcef995dd1 100644 --- a/packages/xrpl/src/models/transactions/AMMBid.ts +++ b/packages/xrpl/src/models/transactions/AMMBid.ts @@ -97,8 +97,7 @@ export function validateAMMBid(tx: Record): void { ) } validateAuthAccounts( - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS - tx.Account as string, + tx.Account, // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS tx.AuthAccounts as Array>, ) diff --git a/packages/xrpl/src/models/transactions/accountDelete.ts b/packages/xrpl/src/models/transactions/accountDelete.ts index 1af47685d7..b4c2eef158 100644 --- a/packages/xrpl/src/models/transactions/accountDelete.ts +++ b/packages/xrpl/src/models/transactions/accountDelete.ts @@ -52,8 +52,7 @@ export function validateAccountDelete(tx: Record): void { validateCredentialsList( tx.CredentialIDs, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check - tx.TransactionType as string, + tx.TransactionType, true, MAX_AUTHORIZED_CREDENTIALS, ) diff --git a/packages/xrpl/src/models/transactions/depositPreauth.ts b/packages/xrpl/src/models/transactions/depositPreauth.ts index cc2c807f48..2c4a56a46e 100644 --- a/packages/xrpl/src/models/transactions/depositPreauth.ts +++ b/packages/xrpl/src/models/transactions/depositPreauth.ts @@ -70,16 +70,14 @@ export function validateDepositPreauth(tx: Record): void { } else if (tx.AuthorizeCredentials !== undefined) { validateCredentialsList( tx.AuthorizeCredentials, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check - tx.TransactionType as string, + tx.TransactionType, false, MAX_AUTHORIZED_CREDENTIALS, ) } else if (tx.UnauthorizeCredentials !== undefined) { validateCredentialsList( tx.UnauthorizeCredentials, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check - tx.TransactionType as string, + tx.TransactionType, false, MAX_AUTHORIZED_CREDENTIALS, ) diff --git a/packages/xrpl/src/models/transactions/escrowFinish.ts b/packages/xrpl/src/models/transactions/escrowFinish.ts index cfd0424e3c..fb4a59f963 100644 --- a/packages/xrpl/src/models/transactions/escrowFinish.ts +++ b/packages/xrpl/src/models/transactions/escrowFinish.ts @@ -53,8 +53,7 @@ export function validateEscrowFinish(tx: Record): void { validateCredentialsList( tx.CredentialIDs, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check - tx.TransactionType as string, + tx.TransactionType, true, MAX_AUTHORIZED_CREDENTIALS, ) diff --git a/packages/xrpl/src/models/transactions/payment.ts b/packages/xrpl/src/models/transactions/payment.ts index 9fb4529cab..5210bf816c 100644 --- a/packages/xrpl/src/models/transactions/payment.ts +++ b/packages/xrpl/src/models/transactions/payment.ts @@ -186,8 +186,7 @@ export function validatePayment(tx: Record): void { validateCredentialsList( tx.CredentialIDs, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check - tx.TransactionType as string, + tx.TransactionType, true, MAX_AUTHORIZED_CREDENTIALS, ) @@ -264,7 +263,10 @@ function isPathStep(pathStep: Record): boolean { return false } -function isPath(path: Array>): boolean { +function isPath(path: unknown): path is Path { + if (!Array.isArray(path) || path.length === 0) { + return false + } for (const pathStep of path) { if (!isPathStep(pathStep)) { return false @@ -273,7 +275,7 @@ function isPath(path: Array>): boolean { return true } -function isPaths(paths: Array>>): boolean { +function isPaths(paths: unknown): paths is Path[] { if (!Array.isArray(paths) || paths.length === 0) { return false } diff --git a/packages/xrpl/src/models/transactions/paymentChannelClaim.ts b/packages/xrpl/src/models/transactions/paymentChannelClaim.ts index 69146ab1f3..26369747c6 100644 --- a/packages/xrpl/src/models/transactions/paymentChannelClaim.ts +++ b/packages/xrpl/src/models/transactions/paymentChannelClaim.ts @@ -152,8 +152,7 @@ export function validatePaymentChannelClaim(tx: Record): void { validateCredentialsList( tx.CredentialIDs, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check - tx.TransactionType as string, + tx.TransactionType, true, MAX_AUTHORIZED_CREDENTIALS, ) diff --git a/packages/xrpl/src/models/transactions/permissionedDomainSet.ts b/packages/xrpl/src/models/transactions/permissionedDomainSet.ts index 0fedb96a83..9e6319bb83 100644 --- a/packages/xrpl/src/models/transactions/permissionedDomainSet.ts +++ b/packages/xrpl/src/models/transactions/permissionedDomainSet.ts @@ -41,8 +41,7 @@ export function validatePermissionedDomainSet( validateCredentialsList( tx.AcceptedCredentials, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check - tx.TransactionType as string, + tx.TransactionType, // PermissionedDomainSet uses AuthorizeCredential nested objects only, strings are not allowed false, // PermissionedDomainSet uses at most 10 accepted credentials. This is different from Credential-feature transactions. diff --git a/packages/xrpl/src/models/transactions/signerListSet.ts b/packages/xrpl/src/models/transactions/signerListSet.ts index f264d55b2f..13a228aec2 100644 --- a/packages/xrpl/src/models/transactions/signerListSet.ts +++ b/packages/xrpl/src/models/transactions/signerListSet.ts @@ -1,7 +1,7 @@ import { ValidationError } from '../../errors' import { SignerEntry } from '../common' -import { BaseTransaction, validateBaseTransaction } from './common' +import { BaseTransaction, isArray, validateBaseTransaction } from './common' /** * The SignerListSet transaction creates, replaces, or removes a list of @@ -56,7 +56,7 @@ export function validateSignerListSet(tx: Record): void { throw new ValidationError('SignerListSet: missing field SignerEntries') } - if (!Array.isArray(tx.SignerEntries)) { + if (!isArray(tx.SignerEntries)) { throw new ValidationError('SignerListSet: invalid SignerEntries') } diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index a7661ea990..797d196546 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -141,41 +141,46 @@ export function setValidAddresses(tx: Transaction): void { * @param tagField - The field name for the tag in the transaction object. * @throws {ValidationError} If the tag field does not match the tag of the account address. */ -function validateAccountAddress( - tx: Transaction, - accountField: string, - tagField: string, -): void { +function validateAccountAddress< + T extends Transaction, + K extends keyof T & string, + K2 extends keyof T & string, +>(tx: T, accountField: K, tagField: K2): void { + const val = tx[accountField] + + if (typeof val !== 'string') { + throw new Error(`${accountField} must be a string`) + } // if X-address is given, convert it to classic address - const { classicAccount, tag } = getClassicAccountAndTag(tx[accountField]) - // eslint-disable-next-line no-param-reassign -- param reassign is safe - tx[accountField] = classicAccount + const { classicAccount, tag } = getClassicAccountAndTag(val) + // eslint-disable-next-line no-param-reassign, @typescript-eslint/consistent-type-assertions -- param reassign is safe + ;(tx as Record)[accountField] = classicAccount if (tag != null && tag !== false) { - if (tx[tagField] && tx[tagField] !== tag) { + if (tagField in tx && tx[tagField] !== tag) { throw new ValidationError( `The ${tagField}, if present, must match the tag of the ${accountField} X-address`, ) } - // eslint-disable-next-line no-param-reassign -- param reassign is safe - tx[tagField] = tag + // eslint-disable-next-line no-param-reassign, @typescript-eslint/consistent-type-assertions -- param reassign is safe + ;(tx as Record)[tagField] = tag } } /** * Retrieves the classic account and tag from an account address. * - * @param Account - The account address. + * @param account - The account address. * @param [expectedTag] - The expected tag for the account address. * @returns The classic account and tag. * @throws {ValidationError} If the address includes a tag that does not match the tag specified in the transaction. */ function getClassicAccountAndTag( - Account: string, + account: string, expectedTag?: number, ): ClassicAccountAndTag { - if (isValidXAddress(Account)) { - const classic = xAddressToClassicAddress(Account) + if (isValidXAddress(account)) { + const classic = xAddressToClassicAddress(account) if (expectedTag != null && classic.tag !== expectedTag) { throw new ValidationError( 'address includes a tag that does not match the tag specified in the transaction', @@ -187,7 +192,7 @@ function getClassicAccountAndTag( } } return { - classicAccount: Account, + classicAccount: account, tag: expectedTag, } } @@ -199,7 +204,6 @@ function getClassicAccountAndTag( * @param fieldName - The name of the field to convert.export */ function convertToClassicAddress(tx: Transaction, fieldName: string): void { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- assignment is safe const account = tx[fieldName] if (typeof account === 'string') { const { classicAccount } = getClassicAccountAndTag(account) From c3405e0009188024313a839e7f0411661b7a088c Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 16 Apr 2025 13:48:33 -0400 Subject: [PATCH 68/73] fix autofill --- packages/xrpl/src/client/index.ts | 4 +-- packages/xrpl/src/sugar/autofill.ts | 44 ++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/packages/xrpl/src/client/index.ts b/packages/xrpl/src/client/index.ts index 86976b6ec1..9e6b589fc9 100644 --- a/packages/xrpl/src/client/index.ts +++ b/packages/xrpl/src/client/index.ts @@ -63,12 +63,12 @@ import { import { setValidAddresses, setNextValidSequenceNumber, - calculateFeePerTransactionType, setLatestValidatedLedgerSequence, checkAccountDeleteBlockers, txNeedsNetworkID, autofillBatchTxn, handleDeliverMax, + getTransactionFee, } from '../sugar/autofill' import { formatBalances } from '../sugar/balances' import { @@ -681,7 +681,7 @@ class Client extends EventEmitter { promises.push(setNextValidSequenceNumber(this, tx)) } if (tx.Fee == null) { - promises.push(calculateFeePerTransactionType(this, tx, signersCount)) + promises.push(getTransactionFee(this, tx, signersCount)) } if (tx.LastLedgerSequence == null) { promises.push(setLatestValidatedLedgerSequence(this, tx)) diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 797d196546..80c93de007 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -266,13 +266,14 @@ async function fetchAccountDeleteFee(client: Client): Promise { * @param client - The client object. * @param tx - The transaction object. * @param [signersCount=0] - The number of signers (default is 0). Only used for multisigning. - * @returns A promise that resolves with void. Modifies the `tx` parameter to give it the calculated fee. + * @returns A promise that returns the fee. */ -export async function calculateFeePerTransactionType( + +async function calculateFeePerTransactionType( client: Client, tx: Transaction, signersCount = 0, -): Promise { +): Promise { // netFee is usually 0.00001 XRP (10 drops) const netFeeXRP = await getFeeXrp(client) const netFeeDrops = xrpToDrops(netFeeXRP) @@ -293,10 +294,15 @@ export async function calculateFeePerTransactionType( ) { baseFee = await fetchAccountDeleteFee(client) } else if (tx.TransactionType === 'Batch') { - baseFee = BigNumber.sum( - baseFee.times(2), - baseFee.times(tx.RawTransactions.length + (tx.BatchSigners?.length ?? 0)), - ) + const rawTxFees = await tx.RawTransactions.reduce(async (acc, rawTxn) => { + const resolvedAcc = await acc + const fee = await calculateFeePerTransactionType( + client, + rawTxn.RawTransaction, + ) + return BigNumber.sum(resolvedAcc, fee) + }, Promise.resolve(new BigNumber(0))) + baseFee = BigNumber.sum(baseFee.times(2), rawTxFees) } /* @@ -314,8 +320,26 @@ export async function calculateFeePerTransactionType( : BigNumber.min(baseFee, maxFeeDrops) // Round up baseFee and return it as a string - // eslint-disable-next-line no-param-reassign, @typescript-eslint/no-magic-numbers -- param reassign is safe, base 10 magic num - tx.Fee = totalFee.dp(0, BigNumber.ROUND_CEIL).toString(10) + + return totalFee.dp(0, BigNumber.ROUND_CEIL) +} + +/** + * Calculates the fee per transaction type and sets it in the transaction. + * + * @param client - The client object. + * @param tx - The transaction object. + * @param [signersCount=0] - The number of signers (default is 0). Only used for multisigning. + * @returns A promise that resolves with void. Modifies the `tx` parameter to give it the calculated fee. + */ +export async function getTransactionFee( + client: Client, + tx: Transaction, + signersCount = 0, +): Promise { + const fee = await calculateFeePerTransactionType(client, tx, signersCount) + // eslint-disable-next-line @typescript-eslint/no-magic-numbers, require-atomic-updates, no-param-reassign -- fine here + tx.Fee = fee.toString(10) } /** @@ -390,7 +414,7 @@ export function handleDeliverMax(tx: Payment): void { // If only DeliverMax is provided, use it to populate the Amount field // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, no-param-reassign -- known RPC-level property + // eslint-disable-next-line no-param-reassign -- known RPC-level property tx.Amount = tx.DeliverMax } From f20f16cde16385c642dff7b59934579d6a63e1f5 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 16 Apr 2025 13:49:07 -0400 Subject: [PATCH 69/73] fix ts issues --- packages/xrpl/src/sugar/autofill.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index 80c93de007..e613d25fb1 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -406,8 +406,6 @@ export async function checkAccountDeleteBlockers( * @throws ValidationError if Amount and DeliverMax are both provided but do not match. */ export function handleDeliverMax(tx: Payment): void { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property - // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level if (tx.DeliverMax != null) { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed here if (tx.Amount == null) { @@ -418,9 +416,6 @@ export function handleDeliverMax(tx: Payment): void { tx.Amount = tx.DeliverMax } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property - // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed here if (tx.Amount != null && tx.Amount !== tx.DeliverMax) { throw new ValidationError( @@ -428,8 +423,6 @@ export function handleDeliverMax(tx: Payment): void { ) } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property - // @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level // eslint-disable-next-line no-param-reassign -- needed here delete tx.DeliverMax } From 808748d1942a661b775356fbaf7dba8644841579 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 16 Apr 2025 13:54:14 -0400 Subject: [PATCH 70/73] more fixes --- packages/xrpl/test/client/autofill.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/xrpl/test/client/autofill.test.ts b/packages/xrpl/test/client/autofill.test.ts index 2f1a92b59f..2956670e01 100644 --- a/packages/xrpl/test/client/autofill.test.ts +++ b/packages/xrpl/test/client/autofill.test.ts @@ -80,7 +80,6 @@ describe('client.autofill', function () { }) it('Validate Payment transaction API v2: Payment Transaction: Specify Only DeliverMax field', async function () { - // @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions paymentTx.DeliverMax = paymentTx.Amount // @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions delete paymentTx.Amount @@ -90,7 +89,6 @@ describe('client.autofill', function () { }) it('Validate Payment transaction API v2: Payment Transaction: identical DeliverMax and Amount fields', async function () { - // @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions paymentTx.DeliverMax = paymentTx.Amount const txResult = await testContext.client.autofill(paymentTx) @@ -100,7 +98,6 @@ describe('client.autofill', function () { }) it('Validate Payment transaction API v2: Payment Transaction: differing DeliverMax and Amount fields', async function () { - // @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions paymentTx.DeliverMax = '6789' paymentTx.Amount = '1234' From d1a4a4193df44fae4a3d37e3384fd58794055a5c Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 16 Apr 2025 13:57:54 -0400 Subject: [PATCH 71/73] more fixes --- packages/xrpl/test/integration/requests/accountTx.test.ts | 1 - packages/xrpl/test/integration/transactions/payment.test.ts | 2 -- 2 files changed, 3 deletions(-) diff --git a/packages/xrpl/test/integration/requests/accountTx.test.ts b/packages/xrpl/test/integration/requests/accountTx.test.ts index a0af38444b..4d578d8603 100644 --- a/packages/xrpl/test/integration/requests/accountTx.test.ts +++ b/packages/xrpl/test/integration/requests/accountTx.test.ts @@ -100,7 +100,6 @@ describe('account_tx', function () { responseTx.Flags, responseTx.TransactionType, responseTx.Account, - // @ts-expect-error -- DeliverMax is a valid field on Payment response responseTx.DeliverMax, responseTx.Destination, ], diff --git a/packages/xrpl/test/integration/transactions/payment.test.ts b/packages/xrpl/test/integration/transactions/payment.test.ts index 2cccfc2c77..2a076b8eb8 100644 --- a/packages/xrpl/test/integration/transactions/payment.test.ts +++ b/packages/xrpl/test/integration/transactions/payment.test.ts @@ -74,7 +74,6 @@ describe('Payment', function () { it( 'Validate Payment transaction API v2: Payment Transaction: Specify Only DeliverMax field', async () => { - // @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions paymentTx.DeliverMax = paymentTx.Amount // @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions delete paymentTx.Amount @@ -94,7 +93,6 @@ describe('Payment', function () { it( 'Validate Payment transaction API v2: Payment Transaction: identical DeliverMax and Amount fields', async () => { - // @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions paymentTx.DeliverMax = paymentTx.Amount const result = await testTransaction( From b2e11222537e9ce2ed59aee08f7ca0ac7f4281a9 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 17 Apr 2025 13:27:36 -0400 Subject: [PATCH 72/73] respond to comments --- packages/ripple-binary-codec/src/binary.ts | 3 --- .../ripple-binary-codec/src/types/hash.ts | 3 +++ packages/xrpl/src/Wallet/batchSigner.ts | 3 --- packages/xrpl/src/models/utils/flags.ts | 23 ++++++++++--------- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/ripple-binary-codec/src/binary.ts b/packages/ripple-binary-codec/src/binary.ts index 420d2bc138..f2a9055ae1 100644 --- a/packages/ripple-binary-codec/src/binary.ts +++ b/packages/ripple-binary-codec/src/binary.ts @@ -210,9 +210,6 @@ function signingBatchData(batch: BatchObject): Uint8Array { bytesList.put(flags) bytesList.put(txIDsLength) batch.txIDs.forEach((txID: string) => { - if (!/^[A-F0-9]{64}$/i.test(txID)) { - throw new Error(`Invalid transaction ID format: ${txID}`) - } bytesList.put(coreTypes.Hash256.from(txID).toBytes()) }) diff --git a/packages/ripple-binary-codec/src/types/hash.ts b/packages/ripple-binary-codec/src/types/hash.ts index 8643578a6a..67a9a0ddeb 100644 --- a/packages/ripple-binary-codec/src/types/hash.ts +++ b/packages/ripple-binary-codec/src/types/hash.ts @@ -27,6 +27,9 @@ class Hash extends Comparable { } if (typeof value === 'string') { + if (!/^[A-F0-9]*$/i.test(value)) { + throw new Error(`Invalid hash string ${value}`) + } return new this(hexToBytes(value)) } diff --git a/packages/xrpl/src/Wallet/batchSigner.ts b/packages/xrpl/src/Wallet/batchSigner.ts index e4fe4f5b7d..d5cbbd293e 100644 --- a/packages/xrpl/src/Wallet/batchSigner.ts +++ b/packages/xrpl/src/Wallet/batchSigner.ts @@ -36,7 +36,6 @@ export function signMultiBatch( multisignAddress = wallet.classicAddress } - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS if (transaction.TransactionType !== 'Batch') { throw new ValidationError('Must be a Batch transaction.') } @@ -188,8 +187,6 @@ function getTransactionWithAllBatchSigners(transactions: Batch[]): Batch { /** * If presented in binary form, the BatchSigners array must be sorted based on * the numeric value of the signer addresses, with the lowest value first. - * (If submitted as JSON, the submit_multisigned method handles this automatically.) - * https://xrpl.org/multi-signing.html. * * @param left - A BatchSigner to compare with. * @param right - A second BatchSigner to compare with. diff --git a/packages/xrpl/src/models/utils/flags.ts b/packages/xrpl/src/models/utils/flags.ts index 24dce07e70..46cd3527d9 100644 --- a/packages/xrpl/src/models/utils/flags.ts +++ b/packages/xrpl/src/models/utils/flags.ts @@ -100,34 +100,35 @@ export function setTransactionFlagsToNumber(tx: Transaction): void { * @returns A numerical representation of a Transaction's Flags */ export function convertTxFlagsToNumber(tx: Transaction): number { - if (!tx.Flags) { + const txFlags = tx.Flags + if (txFlags == null) { return 0 } - if (typeof tx.Flags === 'number') { - return tx.Flags + if (typeof txFlags === 'number') { + return txFlags } if (isTxToFlagKey(tx.TransactionType)) { const flagEnum = txToFlag[tx.TransactionType] - return Object.keys(tx.Flags).reduce((resultFlags, flag) => { - if (flagEnum[flag] == null) { - throw new ValidationError( - `Invalid flag ${flag}. Valid flags are ${JSON.stringify(flagEnum)}`, - ) + return Object.keys(txFlags).reduce((resultFlags, flag) => { + if (flagEnum[flag] == null && GlobalFlags[flag] == null) { + throw new ValidationError(`Invalid flag ${flag}.`) } - return tx.Flags?.[flag] ? resultFlags | flagEnum[flag] : resultFlags + return txFlags[flag] + ? resultFlags | (flagEnum[flag] || GlobalFlags[flag]) + : resultFlags }, 0) } - return Object.keys(tx.Flags).reduce((resultFlags, flag) => { + return Object.keys(txFlags).reduce((resultFlags, flag) => { if (GlobalFlags[flag] == null) { throw new ValidationError( `Invalid flag ${flag}. Valid flags are ${JSON.stringify(GlobalFlags)}`, ) } - return tx.Flags?.[flag] ? resultFlags | GlobalFlags[flag] : resultFlags + return txFlags[flag] ? resultFlags | GlobalFlags[flag] : resultFlags }, 0) } From e19cc517af8ec294a1b02d24afe3ab6fda60e5ea Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 17 Apr 2025 16:57:44 -0400 Subject: [PATCH 73/73] disable --- packages/xrpl/src/Wallet/batchSigner.ts | 1 + packages/xrpl/src/sugar/autofill.ts | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/packages/xrpl/src/Wallet/batchSigner.ts b/packages/xrpl/src/Wallet/batchSigner.ts index d5cbbd293e..3e176fd758 100644 --- a/packages/xrpl/src/Wallet/batchSigner.ts +++ b/packages/xrpl/src/Wallet/batchSigner.ts @@ -36,6 +36,7 @@ export function signMultiBatch( multisignAddress = wallet.classicAddress } + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- for JS purposes if (transaction.TransactionType !== 'Batch') { throw new ValidationError('Must be a Batch transaction.') } diff --git a/packages/xrpl/src/sugar/autofill.ts b/packages/xrpl/src/sugar/autofill.ts index bfd8885ebd..ef251216c4 100644 --- a/packages/xrpl/src/sugar/autofill.ts +++ b/packages/xrpl/src/sugar/autofill.ts @@ -461,24 +461,28 @@ export async function autofillBatchTxn( if (txn.Fee == null) { txn.Fee = '0' + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- for JS purposes } else if (txn.Fee !== '0') { throw new XrplError('Must have `Fee of "0" in inner Batch transaction.') } if (txn.SigningPubKey == null) { txn.SigningPubKey = '' + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- for JS purposes } else if (txn.SigningPubKey !== '') { throw new XrplError( 'Must have `SigningPubKey` of "" in inner Batch transaction.', ) } + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- for JS purposes if (txn.TxnSignature != null) { throw new XrplError( 'Must not have `TxnSignature` in inner Batch transaction.', ) } + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- for JS purposes if (txn.Signers != null) { throw new XrplError('Must not have `Signers` in inner Batch transaction.') }