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

PermissionedDomain XLS-80d #2874

Merged
merged 33 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0169b41
models for PermissionedDomain amendment
ckeshava Nov 19, 2024
f99d415
remove old comment
ckeshava Jan 8, 2025
76e5d09
Apply suggestions from code review
ckeshava Jan 8, 2025
0ad5503
code suggestions from rabbit AI
ckeshava Jan 8, 2025
6a543f8
Include updates for DynamicNFT amendment
ckeshava Jan 14, 2025
fa3b710
include PD amendment in config file
ckeshava Jan 14, 2025
84061c0
Additional unit tests for PDSet txn
ckeshava Jan 14, 2025
035bf0d
Update packages/xrpl/src/models/transactions/permissionedDomainSet.ts
ckeshava Jan 14, 2025
ce9193c
fix linter errors. Use AuthorizeCreds nested object format
ckeshava Jan 14, 2025
cf772b9
refactor: use validateCredsList method for PDSet.AcceptedCreds field
ckeshava Jan 15, 2025
98d9513
include description of method parameters
ckeshava Jan 15, 2025
da655b2
fix: update the containsDuplicates method to handle nested objects
ckeshava Jan 16, 2025
2697a21
remove the use of lodash dependency
ckeshava Jan 16, 2025
81551b0
Merge branch 'main' into xls_80d
ckeshava Jan 16, 2025
c619920
refactor: remove the default value in validateCredentialsList
ckeshava Jan 17, 2025
2316945
refactor: containsDup method
ckeshava Jan 17, 2025
94c0e37
fix linter issues
ckeshava Jan 18, 2025
7f0baad
add descriptions for the PD ledger object
ckeshava Feb 3, 2025
2080c21
address PR comments
ckeshava Feb 3, 2025
1311219
Merge branch 'main' into xls_80d
ckeshava Feb 3, 2025
6d7905f
pacify the linter
ckeshava Feb 3, 2025
2b3580a
remvoe the usage of inner functions
ckeshava Feb 4, 2025
9154151
address PR comments
ckeshava Feb 6, 2025
877aa20
Accomodate new "git" field in the ServerState RPC response
ckeshava Feb 6, 2025
5ee6c1a
update the serverState RPC response with network_id field
ckeshava Feb 6, 2025
c4df44c
Merge branch 'main' into xls_80d
ckeshava Feb 6, 2025
86702e0
update the removeKeys in the comparisons of serverState, serverInfo u…
ckeshava Feb 6, 2025
e9fb8f6
Update packages/xrpl/test/integration/transactions/permissionedDomain…
ckeshava Feb 7, 2025
cbe6b56
Update packages/xrpl/test/integration/transactions/permissionedDomain…
ckeshava Feb 7, 2025
8d0cc28
Merge branch 'main' into xls_80d
ckeshava Feb 7, 2025
9d0e662
address PR commetns
ckeshava Feb 7, 2025
7d1a8d4
fix: update variable names in tests
ckeshava Feb 7, 2025
3dfeaf1
change variable names
ckeshava Feb 7, 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
1 change: 1 addition & 0 deletions .ci-config/rippled.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,4 @@ fixInnerObjTemplate2
fixEnforceNFTokenTrustline
fixReducedOffersV2
DynamicNFT
PermissionedDomains
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ From the top-level xrpl.js folder (one level above `packages`), run the followin
```bash
npm install
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
docker run -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:2.3.0-rc1 -c 'rippled -a'
docker run -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:develop -c 'rippled -a'
npm run build
npm run test:integration
```
Expand All @@ -76,7 +76,7 @@ Breaking down the command:
`--name rippled_standalone` is an instance name for clarity
* `--volume $PWD/.ci-config:/etc/opt/ripple/` identifies the `rippled.cfg` and `validators.txt` to import. It must be an absolute path, so we use `$PWD` instead of `./`.
* `rippleci/rippled` is an image that is regularly updated with the latest `rippled` releases
* `--entrypoint bash rippleci/rippled:2.3.0-rc1` manually overrides the entrypoint (for versions of rippled >= 2.3.0)
* `--entrypoint bash rippleci/rippled:develop` manually overrides the entrypoint (for the latest version of rippled on the `develop` branch)
* `-c 'rippled -a'` provides the bash command to start `rippled` in standalone mode from the manual entrypoint

### Browser Tests
Expand All @@ -92,7 +92,7 @@ This should be run from the `xrpl.js` top level folder (one above the `packages`
```bash
npm run build
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
docker run -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:2.3.0-rc1 -c 'rippled -a'
docker run -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:develop -c 'rippled -a'
npm run test:browser
```

Expand Down
22 changes: 22 additions & 0 deletions packages/ripple-binary-codec/src/enums/definitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,16 @@
"type": "Hash256"
}
],
[
"DomainID",
{
"nth": 34,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"type": "Hash256"
}
],
[
"hash",
{
Expand Down Expand Up @@ -2530,6 +2540,15 @@
"type": "STArray"
}
],
[
"AcceptedCredentials", {
"nth": 28,
"isVLEncoded": false,
"isSerialized": true,
"isSigningField": true,
"type": "STArray"
}
],
[
"CloseResolution",
{
Expand Down Expand Up @@ -2863,6 +2882,7 @@
"Oracle": 128,
"Credential": 129,
"PayChannel": 120,
"PermissionedDomain": 130,
"RippleState": 114,
"SignerList": 83,
"Ticket": 84,
Expand Down Expand Up @@ -3094,6 +3114,8 @@
"PaymentChannelClaim": 15,
"PaymentChannelCreate": 13,
"PaymentChannelFund": 14,
"PermissionedDomainSet": 62,
"PermissionedDomainDelete": 63,
"SetFee": 101,
"SetRegularKey": 5,
"SignerListSet": 12,
Expand Down
7 changes: 5 additions & 2 deletions packages/xrpl/HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ 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-69](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069-simulate))

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

### Added
* Support for the `simulate` RPC ([XLS-69](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069-simulate))
### Fixed
* Include `network_id` field in the `server_state` response interface.


## 4.1.0 (2024-12-23)

Expand Down
3 changes: 3 additions & 0 deletions packages/xrpl/src/models/ledger/LedgerEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import NegativeUNL from './NegativeUNL'
import Offer from './Offer'
import Oracle from './Oracle'
import PayChannel from './PayChannel'
import PermissionedDomain from './PermissionedDomain'
import RippleState from './RippleState'
import SignerList from './SignerList'
import Ticket from './Ticket'
Expand All @@ -35,6 +36,7 @@ type LedgerEntry =
| Offer
| Oracle
| PayChannel
| PermissionedDomain
| RippleState
| SignerList
| Ticket
Expand All @@ -61,6 +63,7 @@ type LedgerEntryFilter =
| 'offer'
| 'oracle'
| 'payment_channel'
| 'permissioned_domain'
| 'signer_list'
| 'state'
| 'ticket'
Expand Down
29 changes: 29 additions & 0 deletions packages/xrpl/src/models/ledger/PermissionedDomain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { AuthorizeCredential } from '../common'

import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'

export default interface PermissionedDomain
extends BaseLedgerEntry,
HasPreviousTxnID {
/* The ledger object's type (PermissionedDomain). */
LedgerEntryType: 'PermissionedDomain'

/* The account that controls the settings of the domain. */
Owner: string

/* The credentials that are accepted by the domain.
Ownership of one of these credentials automatically
makes you a member of the domain. */
AcceptedCredentials: AuthorizeCredential[]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type name is really confusing here - can we alias it or something?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to use the AuthorizeCredential name because I imported it from the Credential-related file. Please check the earlier PR review comments from @achowdhry-ripple in this page

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a preference on the alias name?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mvadari I'd like to discuss this issue offline. I'll merge this PR at the moment because explorer changes need the client library


/* Flag values associated with this object. */
Flags: 0

/* Owner account's directory page containing the PermissionedDomain object. */
OwnerNode: string

/* The Sequence value of the PermissionedDomainSet
transaction that created this domain. Used in combination
with the Account to identify this domain. */
Sequence: number
}
1 change: 1 addition & 0 deletions packages/xrpl/src/models/methods/serverState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface ServerStateResponse extends BaseResponse {
load_factor_fee_queue?: number
load_factor_fee_reference?: number
load_factor_server?: number
network_id: number
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add this to the changelog as a fix

peer_disconnects?: string
peer_disconnects_resources?: string
peers: number
Expand Down
2 changes: 2 additions & 0 deletions packages/xrpl/src/models/transactions/accountDelete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
validateCredentialsList,
validateOptionalField,
validateRequiredField,
MAX_AUTHORIZED_CREDENTIALS,
} from './common'

/**
Expand Down Expand Up @@ -54,5 +55,6 @@ export function validateAccountDelete(tx: Record<string, unknown>): void {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
tx.TransactionType as string,
true,
MAX_AUTHORIZED_CREDENTIALS,
)
}
58 changes: 49 additions & 9 deletions packages/xrpl/src/models/transactions/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import {
AuthorizeCredential,
Currency,
IssuedCurrencyAmount,
MPTAmount,
Memo,
Signer,
XChainBridge,
MPTAmount,
} from '../common'
import { onlyHasFields } from '../utils'

const MEMO_SIZE = 3
const MAX_CREDENTIALS_LIST_LENGTH = 8
export const MAX_AUTHORIZED_CREDENTIALS = 8
const MAX_CREDENTIAL_BYTE_LENGTH = 64
const MAX_CREDENTIAL_TYPE_LENGTH = MAX_CREDENTIAL_BYTE_LENGTH * 2

Expand Down Expand Up @@ -134,7 +134,9 @@ export function isIssuedCurrency(
* @param input - The input to check the form and type of
* @returns Whether the AuthorizeCredential is properly formed
*/
function isAuthorizeCredential(input: unknown): input is AuthorizeCredential {
export function isAuthorizeCredential(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function's name is too specific now that it is also being used for PDs

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name appropriately suggests the intention. Since PDSet transaction also uses AcceptedCredentials as the field name, users can understand the interpretation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's AcceptedCredentials, not AuthorizeCredentials there. That's my point.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@achowdhry-ripple If I rename this to AcceptedCredentials, will it confuse the Credential's usage? Should I rename it to isValidCredential instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mvadari I'd like to discuss this issue offline. I'll merge this PR at the moment because explorer changes need the client library

input: unknown,
): input is AuthorizeCredential {
return (
isRecord(input) &&
isRecord(input.Credential) &&
Expand Down Expand Up @@ -455,13 +457,16 @@ export function validateCredentialType(tx: Record<string, unknown>): void {
* @param credentials An array of credential IDs to check for errors
* @param transactionType The transaction type to include in error messages
* @param isStringID Toggle for if array contains IDs instead of AuthorizeCredential objects
* @param maxCredentials The maximum length of the credentials array.
* PermissionedDomainSet transaction uses 10, other transactions use 8.
* @throws Validation Error if the formatting is incorrect
*/
// eslint-disable-next-line max-lines-per-function -- separating logic further will add unnecessary complexity
// eslint-disable-next-line max-lines-per-function, max-params -- separating logic further will add unnecessary complexity
export function validateCredentialsList(
credentials: unknown,
transactionType: string,
isStringID: boolean,
maxCredentials: number,
): void {
if (credentials == null) {
return
Expand All @@ -471,9 +476,9 @@ export function validateCredentialsList(
`${transactionType}: Credentials must be an array`,
)
}
if (credentials.length > MAX_CREDENTIALS_LIST_LENGTH) {
if (credentials.length > maxCredentials) {
throw new ValidationError(
`${transactionType}: Credentials length cannot exceed ${MAX_CREDENTIALS_LIST_LENGTH} elements`,
`${transactionType}: Credentials length cannot exceed ${maxCredentials} elements`,
)
} else if (credentials.length === 0) {
throw new ValidationError(
Expand All @@ -500,7 +505,42 @@ export function validateCredentialsList(
}
}

function containsDuplicates(objectList: object[]): boolean {
const objSet = new Set(objectList.map((obj) => JSON.stringify(obj)))
return objSet.size !== objectList.length
// Type guard to ensure we're working with AuthorizeCredential[]
// Note: This is not a rigorous type-guard. A more thorough solution would be to iterate over the array and check each item.
function isAuthorizeCredentialArray(
list: AuthorizeCredential[] | string[],
): list is AuthorizeCredential[] {
return typeof list[0] !== 'string'
}
Comment on lines +508 to +514
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve type guard implementation.

The current type guard implementation is not rigorous as it only checks the first element. A more thorough solution would be to iterate over the array and check each item.

-function isAuthorizeCredentialArray(
+function isAuthorizeCredentialArray(
   list: AuthorizeCredential[] | string[],
 ): list is AuthorizeCredential[] {
-  return typeof list[0] !== 'string'
+  return list.length > 0 && list.every((item) => typeof item !== 'string')
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Type guard to ensure we're working with AuthorizeCredential[]
// Note: This is not a rigorous type-guard. A more thorough solution would be to iterate over the array and check each item.
function isAuthorizeCredentialArray(
list: AuthorizeCredential[] | string[],
): list is AuthorizeCredential[] {
return typeof list[0] !== 'string'
}
// Type guard to ensure we're working with AuthorizeCredential[]
// Note: This is not a rigorous type-guard. A more thorough solution would be to iterate over the array and check each item.
function isAuthorizeCredentialArray(
list: AuthorizeCredential[] | string[],
): list is AuthorizeCredential[] {
- return typeof list[0] !== 'string'
+ return list.length > 0 && list.every((item) => typeof item !== 'string')
}


/**
* Check if an array of objects contains any duplicates.
*
* @param objectList - Array of objects to check for duplicates
* @returns True if duplicates exist, false otherwise
*/
export function containsDuplicates(
objectList: AuthorizeCredential[] | string[],
): boolean {
// Case-1: Process a list of string-IDs
if (typeof objectList[0] === 'string') {
const objSet = new Set(objectList.map((obj) => JSON.stringify(obj)))
return objSet.size !== objectList.length
}

// Case-2: Process a list of nested objects
const seen = new Set<string>()

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
}
seen.add(key)
}
}

return false
}
3 changes: 3 additions & 0 deletions packages/xrpl/src/models/transactions/depositPreauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
BaseTransaction,
validateBaseTransaction,
validateCredentialsList,
MAX_AUTHORIZED_CREDENTIALS,
} from './common'

/**
Expand Down Expand Up @@ -72,13 +73,15 @@ export function validateDepositPreauth(tx: Record<string, unknown>): void {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check
tx.TransactionType as string,
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,
false,
MAX_AUTHORIZED_CREDENTIALS,
)
}
}
Expand Down
2 changes: 2 additions & 0 deletions packages/xrpl/src/models/transactions/escrowFinish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
validateBaseTransaction,
validateCredentialsList,
validateRequiredField,
MAX_AUTHORIZED_CREDENTIALS,
} from './common'

/**
Expand Down Expand Up @@ -55,6 +56,7 @@ export function validateEscrowFinish(tx: Record<string, unknown>): void {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
tx.TransactionType as string,
true,
MAX_AUTHORIZED_CREDENTIALS,
)

if (tx.OfferSequence == null) {
Expand Down
3 changes: 3 additions & 0 deletions packages/xrpl/src/models/transactions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,6 @@ export {
XChainModifyBridgeFlags,
XChainModifyBridgeFlagsInterface,
} from './XChainModifyBridge'

export { PermissionedDomainSet } from './permissionedDomainSet'
export { PermissionedDomainDelete } from './permissionedDomainDelete'
2 changes: 2 additions & 0 deletions packages/xrpl/src/models/transactions/payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
isNumber,
Account,
validateCredentialsList,
MAX_AUTHORIZED_CREDENTIALS,
} from './common'
import type { TransactionMetadataBase } from './metadata'

Expand Down Expand Up @@ -188,6 +189,7 @@ export function validatePayment(tx: Record<string, unknown>): void {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
tx.TransactionType as string,
true,
MAX_AUTHORIZED_CREDENTIALS,
)

if (tx.InvoiceID !== undefined && typeof tx.InvoiceID !== 'string') {
Expand Down
2 changes: 2 additions & 0 deletions packages/xrpl/src/models/transactions/paymentChannelClaim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
GlobalFlags,
validateBaseTransaction,
validateCredentialsList,
MAX_AUTHORIZED_CREDENTIALS,
} from './common'

/**
Expand Down Expand Up @@ -153,6 +154,7 @@ export function validatePaymentChannelClaim(tx: Record<string, unknown>): void {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
tx.TransactionType as string,
true,
MAX_AUTHORIZED_CREDENTIALS,
)

if (tx.Channel === undefined) {
Expand Down
28 changes: 28 additions & 0 deletions packages/xrpl/src/models/transactions/permissionedDomainDelete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
BaseTransaction,
isString,
validateBaseTransaction,
validateRequiredField,
} from './common'

export interface PermissionedDomainDelete extends BaseTransaction {
/* The transaction type (PermissionedDomainDelete). */
TransactionType: 'PermissionedDomainDelete'

/* The domain to delete. */
DomainID: string
}

/**
* Verify the form and type of a PermissionedDomainDelete transaction.
*
* @param tx - The transaction to verify.
* @throws When the transaction is malformed.
*/
export function validatePermissionedDomainDelete(
tx: Record<string, unknown>,
): void {
validateBaseTransaction(tx)

validateRequiredField(tx, 'DomainID', isString)
}
Loading
Loading