Skip to content

Commit 189abc1

Browse files
authored
PermissionedDomain XLS-80d (#2874)
1 parent ce5ca31 commit 189abc1

23 files changed

+496
-14
lines changed

.ci-config/rippled.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,4 @@ fixInnerObjTemplate2
189189
fixEnforceNFTokenTrustline
190190
fixReducedOffersV2
191191
DynamicNFT
192+
PermissionedDomains

CONTRIBUTING.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ From the top-level xrpl.js folder (one level above `packages`), run the followin
6464
```bash
6565
npm install
6666
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
67-
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'
67+
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'
6868
npm run build
6969
npm run test:integration
7070
```
@@ -76,7 +76,7 @@ Breaking down the command:
7676
`--name rippled_standalone` is an instance name for clarity
7777
* `--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 `./`.
7878
* `rippleci/rippled` is an image that is regularly updated with the latest `rippled` releases
79-
* `--entrypoint bash rippleci/rippled:2.3.0-rc1` manually overrides the entrypoint (for versions of rippled >= 2.3.0)
79+
* `--entrypoint bash rippleci/rippled:develop` manually overrides the entrypoint (for the latest version of rippled on the `develop` branch)
8080
* `-c 'rippled -a'` provides the bash command to start `rippled` in standalone mode from the manual entrypoint
8181

8282
### Browser Tests
@@ -92,7 +92,7 @@ This should be run from the `xrpl.js` top level folder (one above the `packages`
9292
```bash
9393
npm run build
9494
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
95-
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'
95+
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'
9696
npm run test:browser
9797
```
9898

packages/ripple-binary-codec/src/enums/definitions.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,16 @@
12501250
"type": "Hash256"
12511251
}
12521252
],
1253+
[
1254+
"DomainID",
1255+
{
1256+
"nth": 34,
1257+
"isVLEncoded": false,
1258+
"isSerialized": true,
1259+
"isSigningField": true,
1260+
"type": "Hash256"
1261+
}
1262+
],
12531263
[
12541264
"hash",
12551265
{
@@ -2530,6 +2540,15 @@
25302540
"type": "STArray"
25312541
}
25322542
],
2543+
[
2544+
"AcceptedCredentials", {
2545+
"nth": 28,
2546+
"isVLEncoded": false,
2547+
"isSerialized": true,
2548+
"isSigningField": true,
2549+
"type": "STArray"
2550+
}
2551+
],
25332552
[
25342553
"CloseResolution",
25352554
{
@@ -2863,6 +2882,7 @@
28632882
"Oracle": 128,
28642883
"Credential": 129,
28652884
"PayChannel": 120,
2885+
"PermissionedDomain": 130,
28662886
"RippleState": 114,
28672887
"SignerList": 83,
28682888
"Ticket": 84,
@@ -3094,6 +3114,8 @@
30943114
"PaymentChannelClaim": 15,
30953115
"PaymentChannelCreate": 13,
30963116
"PaymentChannelFund": 14,
3117+
"PermissionedDomainSet": 62,
3118+
"PermissionedDomainDelete": 63,
30973119
"SetFee": 101,
30983120
"SetRegularKey": 5,
30993121
"SignerListSet": 12,

packages/xrpl/HISTORY.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
66

77
### Added
88
* Adds utility function `convertTxFlagsToNumber`
9+
* Implementation of XLS-80d PermissionedDomain feature.
10+
* Support for the `simulate` RPC ([XLS-69](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069-simulate))
911

1012
### Changed
1113
* Deprecated `setTransactionFlagsToNumber`. Start using convertTxFlagsToNumber instead
1214

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

1619
## 4.1.0 (2024-12-23)
1720

packages/xrpl/src/models/ledger/LedgerEntry.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import NegativeUNL from './NegativeUNL'
1313
import Offer from './Offer'
1414
import Oracle from './Oracle'
1515
import PayChannel from './PayChannel'
16+
import PermissionedDomain from './PermissionedDomain'
1617
import RippleState from './RippleState'
1718
import SignerList from './SignerList'
1819
import Ticket from './Ticket'
@@ -35,6 +36,7 @@ type LedgerEntry =
3536
| Offer
3637
| Oracle
3738
| PayChannel
39+
| PermissionedDomain
3840
| RippleState
3941
| SignerList
4042
| Ticket
@@ -61,6 +63,7 @@ type LedgerEntryFilter =
6163
| 'offer'
6264
| 'oracle'
6365
| 'payment_channel'
66+
| 'permissioned_domain'
6467
| 'signer_list'
6568
| 'state'
6669
| 'ticket'
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { AuthorizeCredential } from '../common'
2+
3+
import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'
4+
5+
export default interface PermissionedDomain
6+
extends BaseLedgerEntry,
7+
HasPreviousTxnID {
8+
/* The ledger object's type (PermissionedDomain). */
9+
LedgerEntryType: 'PermissionedDomain'
10+
11+
/* The account that controls the settings of the domain. */
12+
Owner: string
13+
14+
/* The credentials that are accepted by the domain.
15+
Ownership of one of these credentials automatically
16+
makes you a member of the domain. */
17+
AcceptedCredentials: AuthorizeCredential[]
18+
19+
/* Flag values associated with this object. */
20+
Flags: 0
21+
22+
/* Owner account's directory page containing the PermissionedDomain object. */
23+
OwnerNode: string
24+
25+
/* The Sequence value of the PermissionedDomainSet
26+
transaction that created this domain. Used in combination
27+
with the Account to identify this domain. */
28+
Sequence: number
29+
}

packages/xrpl/src/models/methods/serverState.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export interface ServerStateResponse extends BaseResponse {
5151
load_factor_fee_queue?: number
5252
load_factor_fee_reference?: number
5353
load_factor_server?: number
54+
network_id: number
5455
peer_disconnects?: string
5556
peer_disconnects_resources?: string
5657
peers: number

packages/xrpl/src/models/transactions/accountDelete.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
validateCredentialsList,
88
validateOptionalField,
99
validateRequiredField,
10+
MAX_AUTHORIZED_CREDENTIALS,
1011
} from './common'
1112

1213
/**
@@ -54,5 +55,6 @@ export function validateAccountDelete(tx: Record<string, unknown>): void {
5455
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- known from base check
5556
tx.TransactionType as string,
5657
true,
58+
MAX_AUTHORIZED_CREDENTIALS,
5759
)
5860
}

packages/xrpl/src/models/transactions/common.ts

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ import {
99
AuthorizeCredential,
1010
Currency,
1111
IssuedCurrencyAmount,
12+
MPTAmount,
1213
Memo,
1314
Signer,
1415
XChainBridge,
15-
MPTAmount,
1616
} from '../common'
1717
import { onlyHasFields } from '../utils'
1818

1919
const MEMO_SIZE = 3
20-
const MAX_CREDENTIALS_LIST_LENGTH = 8
20+
export const MAX_AUTHORIZED_CREDENTIALS = 8
2121
const MAX_CREDENTIAL_BYTE_LENGTH = 64
2222
const MAX_CREDENTIAL_TYPE_LENGTH = MAX_CREDENTIAL_BYTE_LENGTH * 2
2323

@@ -134,7 +134,9 @@ export function isIssuedCurrency(
134134
* @param input - The input to check the form and type of
135135
* @returns Whether the AuthorizeCredential is properly formed
136136
*/
137-
function isAuthorizeCredential(input: unknown): input is AuthorizeCredential {
137+
export function isAuthorizeCredential(
138+
input: unknown,
139+
): input is AuthorizeCredential {
138140
return (
139141
isRecord(input) &&
140142
isRecord(input.Credential) &&
@@ -455,13 +457,16 @@ export function validateCredentialType(tx: Record<string, unknown>): void {
455457
* @param credentials An array of credential IDs to check for errors
456458
* @param transactionType The transaction type to include in error messages
457459
* @param isStringID Toggle for if array contains IDs instead of AuthorizeCredential objects
460+
* @param maxCredentials The maximum length of the credentials array.
461+
* PermissionedDomainSet transaction uses 10, other transactions use 8.
458462
* @throws Validation Error if the formatting is incorrect
459463
*/
460-
// eslint-disable-next-line max-lines-per-function -- separating logic further will add unnecessary complexity
464+
// eslint-disable-next-line max-lines-per-function, max-params -- separating logic further will add unnecessary complexity
461465
export function validateCredentialsList(
462466
credentials: unknown,
463467
transactionType: string,
464468
isStringID: boolean,
469+
maxCredentials: number,
465470
): void {
466471
if (credentials == null) {
467472
return
@@ -471,9 +476,9 @@ export function validateCredentialsList(
471476
`${transactionType}: Credentials must be an array`,
472477
)
473478
}
474-
if (credentials.length > MAX_CREDENTIALS_LIST_LENGTH) {
479+
if (credentials.length > maxCredentials) {
475480
throw new ValidationError(
476-
`${transactionType}: Credentials length cannot exceed ${MAX_CREDENTIALS_LIST_LENGTH} elements`,
481+
`${transactionType}: Credentials length cannot exceed ${maxCredentials} elements`,
477482
)
478483
} else if (credentials.length === 0) {
479484
throw new ValidationError(
@@ -500,7 +505,42 @@ export function validateCredentialsList(
500505
}
501506
}
502507

503-
function containsDuplicates(objectList: object[]): boolean {
504-
const objSet = new Set(objectList.map((obj) => JSON.stringify(obj)))
505-
return objSet.size !== objectList.length
508+
// Type guard to ensure we're working with AuthorizeCredential[]
509+
// Note: This is not a rigorous type-guard. A more thorough solution would be to iterate over the array and check each item.
510+
function isAuthorizeCredentialArray(
511+
list: AuthorizeCredential[] | string[],
512+
): list is AuthorizeCredential[] {
513+
return typeof list[0] !== 'string'
514+
}
515+
516+
/**
517+
* Check if an array of objects contains any duplicates.
518+
*
519+
* @param objectList - Array of objects to check for duplicates
520+
* @returns True if duplicates exist, false otherwise
521+
*/
522+
export function containsDuplicates(
523+
objectList: AuthorizeCredential[] | string[],
524+
): boolean {
525+
// Case-1: Process a list of string-IDs
526+
if (typeof objectList[0] === 'string') {
527+
const objSet = new Set(objectList.map((obj) => JSON.stringify(obj)))
528+
return objSet.size !== objectList.length
529+
}
530+
531+
// Case-2: Process a list of nested objects
532+
const seen = new Set<string>()
533+
534+
if (isAuthorizeCredentialArray(objectList)) {
535+
for (const item of objectList) {
536+
const key = `${item.Credential.Issuer}-${item.Credential.CredentialType}`
537+
// eslint-disable-next-line max-depth -- necessary to check for type-guards
538+
if (seen.has(key)) {
539+
return true
540+
}
541+
seen.add(key)
542+
}
543+
}
544+
545+
return false
506546
}

packages/xrpl/src/models/transactions/depositPreauth.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
BaseTransaction,
66
validateBaseTransaction,
77
validateCredentialsList,
8+
MAX_AUTHORIZED_CREDENTIALS,
89
} from './common'
910

1011
/**
@@ -72,13 +73,15 @@ export function validateDepositPreauth(tx: Record<string, unknown>): void {
7273
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check
7374
tx.TransactionType as string,
7475
false,
76+
MAX_AUTHORIZED_CREDENTIALS,
7577
)
7678
} else if (tx.UnauthorizeCredentials !== undefined) {
7779
validateCredentialsList(
7880
tx.UnauthorizeCredentials,
7981
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- confirmed in base transaction check
8082
tx.TransactionType as string,
8183
false,
84+
MAX_AUTHORIZED_CREDENTIALS,
8285
)
8386
}
8487
}

0 commit comments

Comments
 (0)