Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: parseTransactionFlags unintentionally modifies transaction #2825

Merged
merged 32 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
863e048
remove setTransactions and any reference to modifying a transaction p…
achowdhry-ripple Nov 13, 2024
95f46ce
remove use of setter in autofill
achowdhry-ripple Nov 13, 2024
0f3e67d
changelog and test fixes
achowdhry-ripple Nov 13, 2024
bf4a4ab
add back deprecated function with warnings
achowdhry-ripple Nov 13, 2024
3611629
add new helper function to exported
achowdhry-ripple Nov 13, 2024
951ba19
update readme with deprecated
achowdhry-ripple Nov 13, 2024
803b27d
remove references to deprecated setter
achowdhry-ripple Nov 13, 2024
4078fb8
fix changelog syntax
achowdhry-ripple Nov 13, 2024
a1dcfe2
revert to test old functions
achowdhry-ripple Nov 13, 2024
1a2d37f
lint
achowdhry-ripple Nov 13, 2024
4b872ab
lint for deprecation
achowdhry-ripple Nov 13, 2024
c08214d
Merge branch 'main' into parse-transaction-flags-bug
achowdhry-ripple Nov 25, 2024
fa078fd
remove unsafe assertions
achowdhry-ripple Dec 20, 2024
73eda68
separate null check
achowdhry-ripple Dec 23, 2024
501b845
clean up tests
achowdhry-ripple Dec 23, 2024
89375a1
remove outdated logic
achowdhry-ripple Jan 3, 2025
30431b0
fix history md
achowdhry-ripple Jan 3, 2025
0f5c9d0
Merge branch 'main' into parse-transaction-flags-bug
achowdhry-ripple Jan 3, 2025
583413f
fix tests after merge conflicts
achowdhry-ripple Jan 3, 2025
517a034
Update packages/xrpl/HISTORY.md
achowdhry-ripple Jan 16, 2025
86138cc
Update packages/xrpl/src/models/utils/flags.ts
achowdhry-ripple Jan 16, 2025
fc3a79f
Update packages/xrpl/src/models/utils/flags.ts
achowdhry-ripple Jan 16, 2025
128dc20
Update packages/xrpl/src/models/utils/flags.ts
achowdhry-ripple Jan 16, 2025
904c5e0
Update packages/xrpl/src/models/utils/flags.ts
achowdhry-ripple Jan 16, 2025
642d313
Update packages/xrpl/src/models/utils/flags.ts
achowdhry-ripple Jan 16, 2025
37b99af
Update packages/xrpl/src/models/utils/flags.ts
achowdhry-ripple Jan 16, 2025
e501f0c
Update packages/xrpl/src/models/utils/flags.ts
achowdhry-ripple Jan 16, 2025
dad7c29
Update packages/xrpl/src/models/utils/flags.ts
achowdhry-ripple Jan 16, 2025
5a77c62
Update packages/xrpl/test/models/utils.test.ts
achowdhry-ripple Jan 16, 2025
127e216
rename a test per pr comment
achowdhry-ripple Jan 16, 2025
fb67a10
lint fixes
achowdhry-ripple Jan 16, 2025
eb98875
Update packages/xrpl/test/models/utils.test.ts
achowdhry-ripple Jan 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/xrpl/HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xrpl-announce) for release announcements. We recommend that xrpl.js (ripple-lib) users stay up-to-date with the latest stable release.

## Unreleased Changes
## Unreleased
ckeshava marked this conversation as resolved.
Show resolved Hide resolved

### Added
* Adds utility function `convertTxFlagsToNumber`

### Changed
* Deprecated `setTransactionFlagsToNumber`. Start using convertTxFlagsToNumber instead

## 4.1.0 (2024-12-23)

Expand Down
4 changes: 2 additions & 2 deletions packages/xrpl/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import type {
OnEventToListenerMap,
} from '../models/methods/subscribe'
import type { SubmittableTransaction } from '../models/transactions'
import { setTransactionFlagsToNumber } from '../models/utils/flags'
import { convertTxFlagsToNumber } from '../models/utils/flags'
import {
ensureClassicAddress,
submitRequest,
Expand Down Expand Up @@ -665,7 +665,7 @@ class Client extends EventEmitter<EventTypes> {
const tx = { ...transaction }

setValidAddresses(tx)
setTransactionFlagsToNumber(tx)
tx.Flags = convertTxFlagsToNumber(tx)

const promises: Array<Promise<void>> = []
if (tx.NetworkID == null) {
Expand Down
3 changes: 2 additions & 1 deletion packages/xrpl/src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
*/
export * as LedgerEntry from './ledger'
export {
setTransactionFlagsToNumber,
parseAccountRootFlags,
setTransactionFlagsToNumber,
achowdhry-ripple marked this conversation as resolved.
Show resolved Hide resolved
convertTxFlagsToNumber,
parseTransactionFlags,
} from './utils/flags'
export * from './methods'
Expand Down
4 changes: 2 additions & 2 deletions packages/xrpl/src/models/transactions/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { ValidationError } from '../../errors'
import { IssuedCurrencyAmount, Memo } from '../common'
import { isHex } from '../utils'
import { setTransactionFlagsToNumber } from '../utils/flags'
import { convertTxFlagsToNumber } from '../utils/flags'

import { AccountDelete, validateAccountDelete } from './accountDelete'
import { AccountSet, validateAccountSet } from './accountSet'
Expand Down Expand Up @@ -255,7 +255,7 @@ export function validate(transaction: Record<string, unknown>): void {
})

// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- okay here
setTransactionFlagsToNumber(tx as unknown as Transaction)
tx.Flags = convertTxFlagsToNumber(tx as unknown as Transaction)
switch (tx.TransactionType) {
case 'AMMBid':
validateAMMBid(tx)
Expand Down
94 changes: 59 additions & 35 deletions packages/xrpl/src/models/utils/flags.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign -- param reassign is safe */
/* eslint-disable no-bitwise -- flags require bitwise operations */
import { ValidationError } from '../../errors'
import {
Expand All @@ -8,7 +7,6 @@ import {
import { AccountSetTfFlags } from '../transactions/accountSet'
import { AMMDepositFlags } from '../transactions/AMMDeposit'
import { AMMWithdrawFlags } from '../transactions/AMMWithdraw'
import { GlobalFlags } from '../transactions/common'
import { MPTokenAuthorizeFlags } from '../transactions/MPTokenAuthorize'
import { MPTokenIssuanceCreateFlags } from '../transactions/MPTokenIssuanceCreate'
import { MPTokenIssuanceSetFlags } from '../transactions/MPTokenIssuanceSet'
Expand Down Expand Up @@ -63,37 +61,61 @@ const txToFlag = {
XChainModifyBridge: XChainModifyBridgeFlags,
}

function isTxToFlagKey(
transactionType: string,
): transactionType is keyof typeof txToFlag {
return transactionType in txToFlag
}

/**
* Sets a transaction's flags to its numeric representation.
*
* @deprecated
* This utility function is deprecated.
* Use convertTxFlagsToNumber() instead and use the returned value to modify the Transaction.Flags from the caller.
*
* @param tx - A transaction to set its flags to its numeric representation.
*/
export function setTransactionFlagsToNumber(tx: Transaction): void {
if (tx.Flags == null) {
tx.Flags = 0
return
// eslint-disable-next-line no-console -- intended deprecation warning
console.warn(
'This function is deprecated. Use convertTxFlagsToNumber() instead and use the returned value to modify the Transaction.Flags from the caller.',
)

if (tx.Flags) {
// eslint-disable-next-line no-param-reassign -- intended param reassign in setter, retain old functionality for compatibility
tx.Flags = convertTxFlagsToNumber(tx)
}
}

/**
* Returns a Transaction's Flags as its numeric representation.
*
* @param tx - A Transaction to parse Flags for
* @returns A numerical representation of a Transaction's Flags
*/
export function convertTxFlagsToNumber(tx: Transaction): number {
if (!tx.Flags) {
return 0
}
if (typeof tx.Flags === 'number') {
return
achowdhry-ripple marked this conversation as resolved.
Show resolved Hide resolved
ckeshava marked this conversation as resolved.
Show resolved Hide resolved
return tx.Flags
}

tx.Flags = txToFlag[tx.TransactionType]
? convertFlagsToNumber(tx.Flags, txToFlag[tx.TransactionType])
: 0
}
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)}`,
)
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any -- added ValidationError check for flagEnum
function convertFlagsToNumber(flags: GlobalFlags, flagEnum: any): number {
return Object.keys(flags).reduce((resultFlags, flag) => {
achowdhry-ripple marked this conversation as resolved.
Show resolved Hide resolved
// 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)
return tx.Flags?.[flag] ? resultFlags | flagEnum[flag] : resultFlags
}, 0)
achowdhry-ripple marked this conversation as resolved.
Show resolved Hide resolved
}

return 0
}

/**
Expand All @@ -103,22 +125,24 @@ function convertFlagsToNumber(flags: GlobalFlags, flagEnum: any): number {
* @returns A map with all flags as booleans.
*/
export function parseTransactionFlags(tx: Transaction): object {
setTransactionFlagsToNumber(tx)
if (typeof tx.Flags !== 'number' || !tx.Flags || tx.Flags === 0) {
const flags = convertTxFlagsToNumber(tx)
if (flags === 0) {
return {}
achowdhry-ripple marked this conversation as resolved.
Show resolved Hide resolved
}

const flags = tx.Flags
const flagsMap = {}
const booleanFlagMap = {}

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- safe member access
const flagEnum = txToFlag[tx.TransactionType]
Object.values(flagEnum).forEach((flag) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- safe member access
if (typeof flag === 'string' && isFlagEnabled(flags, flagEnum[flag])) {
flagsMap[flag] = true
}
})
if (istxToFlagKey(tx.TransactionType)) {
const transactionTypeFlags = txToFlag[tx.TransactionType]
Object.values(transactionTypeFlags).forEach((flag) => {
if (
typeof flag === 'string' &&
isFlagEnabled(flags, transactionTypeFlags[flag])
) {
booleanFlagMap[flag] = true
}
achowdhry-ripple marked this conversation as resolved.
Show resolved Hide resolved
})
}

return flagsMap
return booleanFlagMap
}
Loading
Loading