Skip to content

Commit

Permalink
Merge branch 'main' into batch
Browse files Browse the repository at this point in the history
  • Loading branch information
mvadari committed Feb 6, 2025
2 parents c48957d + 991a1d2 commit b519151
Show file tree
Hide file tree
Showing 15 changed files with 510 additions and 100 deletions.
1 change: 1 addition & 0 deletions .ci-config/rippled.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,4 @@ fixNFTokenPageLinks
fixInnerObjTemplate2
fixEnforceNFTokenTrustline
fixReducedOffersV2
DynamicNFT
2 changes: 1 addition & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
name: Node.js CI

env:
RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.3.0-rc1
RIPPLED_DOCKER_IMAGE: rippleci/rippled:develop

on:
push:
Expand Down
1 change: 1 addition & 0 deletions packages/ripple-binary-codec/HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

### Added
* Support for the Price Oracles amendment (XLS-47).
* Support for the `DynamicNFT` amendment (XLS-46)

### Fixed
* Better error handling/error messages for serialization/deserialization errors.
Expand Down
4 changes: 2 additions & 2 deletions packages/ripple-binary-codec/src/enums/definitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2978,7 +2978,7 @@
"nth": 30,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"isSigningField": false,
"type": "STArray"
}
]
Expand Down Expand Up @@ -3051,7 +3051,7 @@
"temARRAY_EMPTY": -253,
"temARRAY_TOO_LARGE": -252,
"temBAD_TRANSFER_FEE": -251,
"temINVALID_BATCH": -250,
"temINVALID_INNER_BATCH": -250,

"tefFAILURE": -199,
"tefALREADY": -198,
Expand Down
9 changes: 8 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

### Added
* Adds utility function `convertTxFlagsToNumber`

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

### Added
* Add support for `Batch` amendment (XLS-56).
Expand All @@ -14,6 +20,7 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
* New `MPTAmount` type support for `Payment` and `Clawback` transactions
* `parseTransactionFlags` as a utility function in the xrpl package to streamline transactions flags-to-map conversion
* Support for XLS-70d (Credentials)
* Support for the `DynamicNFT` amendment (XLS-46)

### Fixed
* `TransactionStream` model supports APIv2
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 @@ -666,7 +666,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,
convertTxFlagsToNumber,
parseTransactionFlags,
} from './utils/flags'
export * from './methods'
Expand Down
5 changes: 5 additions & 0 deletions packages/xrpl/src/models/transactions/NFTokenMint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export enum NFTokenMintFlags {
* issuer.
*/
tfTransferable = 0x00000008,
/**
* If set, indicates that this NFT's URI can be modified.
*/
tfMutable = 0x00000010,
}

/**
Expand All @@ -51,6 +55,7 @@ export interface NFTokenMintFlagsInterface extends GlobalFlagsInterface {
tfOnlyXRP?: boolean
tfTrustLine?: boolean
tfTransferable?: boolean
tfMutable?: boolean
}

/**
Expand Down
67 changes: 67 additions & 0 deletions packages/xrpl/src/models/transactions/NFTokenModify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { ValidationError } from '../../errors'
import { isHex } from '../utils'

import {
BaseTransaction,
validateBaseTransaction,
isAccount,
isString,
validateOptionalField,
Account,
validateRequiredField,
} from './common'

/**
* The NFTokenModify transaction modifies an NFToken's URI
* if its tfMutable is set to true.
*/
export interface NFTokenModify extends BaseTransaction {
TransactionType: 'NFTokenModify'
/**
* Identifies the NFTokenID of the NFToken object that the
* offer references.
*/
NFTokenID: string
/**
* Indicates the AccountID of the account that owns the corresponding NFToken.
* Can be omitted if the owner is the account submitting this transaction
*/
Owner?: Account
/**
* URI that points to the data and/or metadata associated with the NFT.
* This field need not be an HTTP or HTTPS URL; it could be an IPFS URI, a
* magnet link, immediate data encoded as an RFC2379 "data" URL, or even an
* opaque issuer-specific encoding. The URI is NOT checked for validity, but
* the field is limited to a maximum length of 256 bytes.
*
* This field must be hex-encoded. You can use `convertStringToHex` to
* convert this field to the proper encoding.
*
* This field must not be an empty string. Omit it from the transaction or
* set to `null` if you do not use it.
*/
URI?: string | null
}

/**
* Verify the form and type of an NFTokenModify at runtime.
*
* @param tx - An NFTokenModify Transaction.
* @throws When the NFTokenModify is Malformed.
*/
export function validateNFTokenModify(tx: Record<string, unknown>): void {
validateBaseTransaction(tx)

validateRequiredField(tx, 'NFTokenID', isString)
validateOptionalField(tx, 'Owner', isAccount)
validateOptionalField(tx, 'URI', isString)

if (tx.URI !== undefined && typeof tx.URI === 'string') {
if (tx.URI === '') {
throw new ValidationError('NFTokenModify: URI must not be empty string')
}
if (!isHex(tx.URI)) {
throw new ValidationError('NFTokenModify: URI must be in hex format')
}
}
}
1 change: 1 addition & 0 deletions packages/xrpl/src/models/transactions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export {
NFTokenMintFlags,
NFTokenMintFlagsInterface,
} from './NFTokenMint'
export { NFTokenModify, validateNFTokenModify } from './NFTokenModify'
export { OfferCancel } from './offerCancel'
export {
OfferCreateFlags,
Expand Down
10 changes: 8 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 @@ -58,6 +58,7 @@ import {
validateNFTokenCreateOffer,
} from './NFTokenCreateOffer'
import { NFTokenMint, validateNFTokenMint } from './NFTokenMint'
import { NFTokenModify, validateNFTokenModify } from './NFTokenModify'
import { OfferCancel, validateOfferCancel } from './offerCancel'
import { OfferCreate, validateOfferCreate } from './offerCreate'
import { OracleDelete, validateOracleDelete } from './oracleDelete'
Expand Down Expand Up @@ -145,6 +146,7 @@ export type SubmittableTransaction =
| NFTokenCancelOffer
| NFTokenCreateOffer
| NFTokenMint
| NFTokenModify
| OfferCancel
| OfferCreate
| OracleDelete
Expand Down Expand Up @@ -257,7 +259,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 Expand Up @@ -392,6 +394,10 @@ export function validate(transaction: Record<string, unknown>): void {
validateNFTokenMint(tx)
break

case 'NFTokenModify':
validateNFTokenModify(tx)
break

case 'OfferCancel':
validateOfferCancel(tx)
break
Expand Down
97 changes: 63 additions & 34 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 Down Expand Up @@ -65,37 +64,68 @@ 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
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)}`,
)
}

return tx.Flags?.[flag] ? resultFlags | flagEnum[flag] : resultFlags
}, 0)
}

function convertFlagsToNumber(
flags: GlobalFlagsInterface,
flagEnum: object,
): number {
return Object.keys(flags).reduce((resultFlags, flag) => {
if (flagEnum[flag] == null) {
return Object.keys(tx.Flags).reduce((resultFlags, flag) => {
if (GlobalFlags[flag] == null) {
throw new ValidationError(
`flag ${flag} doesn't exist in flagEnum: ${JSON.stringify(flagEnum)}`,
`Invalid flag ${flag}. Valid flags are ${JSON.stringify(GlobalFlags)}`,
)
}

return flags[flag] ? resultFlags | flagEnum[flag] : resultFlags
return tx.Flags?.[flag] ? resultFlags | GlobalFlags[flag] : resultFlags
}, 0)
}

Expand All @@ -106,24 +136,26 @@ function convertFlagsToNumber(
* @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 {}
}

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
}
})
}

return flagsMap
return booleanFlagMap
}

/**
Expand All @@ -140,9 +172,6 @@ export function hasFlag(tx: Transaction, flag: number): boolean {
if (typeof tx.Flags === 'number') {
return isFlagEnabled(tx.Flags, flag)
}
const txFlagNum = convertFlagsToNumber(
tx.Flags,
txToFlag[tx.TransactionType] ?? GlobalFlags,
)
const txFlagNum = convertTxFlagsToNumber(tx)
return isFlagEnabled(txFlagNum, flag)
}
Loading

0 comments on commit b519151

Please sign in to comment.