From a2d754b40f392538cce321768538121d6943a19d Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Wed, 23 Jul 2025 16:48:23 -0700 Subject: [PATCH 1/7] Start fixing up Permission Delegation docs --- docs/concepts/accounts/deleting-accounts.md | 18 +++-- .../protocol/data-types/permission-values.md | 68 +++++++++++++++++++ .../ledger-entry-types/delegate.md | 52 ++++++++++++++ .../protocol/transactions/common-fields.md | 39 ++--------- sidebars.yaml | 1 + 5 files changed, 139 insertions(+), 39 deletions(-) create mode 100644 docs/references/protocol/data-types/permission-values.md create mode 100644 docs/references/protocol/ledger-data/ledger-entry-types/delegate.md diff --git a/docs/concepts/accounts/deleting-accounts.md b/docs/concepts/accounts/deleting-accounts.md index b1a8414e43..3415119f5e 100644 --- a/docs/concepts/accounts/deleting-accounts.md +++ b/docs/concepts/accounts/deleting-accounts.md @@ -19,14 +19,22 @@ After an account has been deleted, it can be re-created in the ledger through th To be deleted, an account must meet the following requirements: - The account's `Sequence` number plus 256 must be less than the current [Ledger Index][]. -- The account must not be linked to any of the following types of [ledger entries](../../references/protocol/ledger-data/ledger-entry-types/index.md) (as a sender or receiver): - - `Escrow` - - `PayChannel` - - `RippleState` - - `Check` +- The account must not have any "deletion blockers" in its owner directory. This includes cases where the account is a sender _or_ receiver of funds. See below for a full list of deletion blockers. - The account must own fewer than 1000 objects in the ledger. - The transaction must pay a special [transaction cost][] equal to at least the [owner reserve](reserves.md) for one item (currently {% $env.PUBLIC_OWNER_RESERVE %}). +### Deletion Blockers + +The following [ledger entry types](../../references/protocol/ledger-data/ledger-entry-types/index.md) are deletion blockers: + +- `Escrow` +- `PayChannel` +- `RippleState` (trust line) +- `Check` +- `PermissionedDomain` _(Requires the [PermissionedDomains amendment][] {% not-enabled /%})_ + +Any other types of ledger entries that an account owns are automatically deleted along with the account. + ## Cost of Deleting {% admonition type="danger" name="Warning" %}The [AccountDelete transaction][]'s transaction cost always applies when the transaction is included in a validated ledger, even if the transaction failed because the account does not meet the requirements to be deleted. To greatly reduce the chances of paying the high transaction cost if the account cannot be deleted, use the `fail_hard` option when submitting an AccountDelete transaction.{% /admonition %} diff --git a/docs/references/protocol/data-types/permission-values.md b/docs/references/protocol/data-types/permission-values.md new file mode 100644 index 0000000000..9d27bf8812 --- /dev/null +++ b/docs/references/protocol/data-types/permission-values.md @@ -0,0 +1,68 @@ +--- +seo: + description: Format for permissions that can be granted to other accounts. +label: + - Permissions +--- +# Permission Values + +The Permission Delegation amendment {% not-enabled /%} defines permissions that can be granted to other accounts. These permissions fall into three categories: + +- **Full Permissions** - Permission to send transactions of any type. +- **Transaction Type Permissions** - Permission to send transactions with the specified [transaction type](../transactions/types/index.md). +- **Granular Permissions** - Permission to send transactions with a specific subset of functionality. + +## Numeric and String Values + +In the [canonical binary format](../binary-format.md) for transactions and ledger data, permission values are stored in a numeric form (specifically, as a 32-bit unsigned integer). However, in JSON they can be specified and returned in string format for convenience, similar to how transaction type names (`TransactionType` fields) work. + +When specifying a permission value in JSON, you can use either the numeric value or the string value. When serving data, + +The numeric value `0` is reserved for "full permissions", meaning permission to send transactions of all types. ***TODO: but can you actually delegate full permissions?*** + +## Transaction Type Permissions + +Transaction Type Permissions have numeric values from 1 to 65536 (216), inclusive. They correspond with known transaction types, except you add 1 when specifying a transaction type as a permission value. For example, the string `"Payment"` corresponds to a `TransactionType` value of `0`, but a `PermissionValue` type of `1`. To grant permissions to make Payment transactions, you can specify either `"PermissionValue": "Payment"` or `"PermissionValue": 1`. + +For a mapping of transaction types known by a server and their corresponding numeric transaction type values, check the `TRANSACTION_TYPES` field in the [server_definitions method][]. + +### List of Non-Delegatable Permissions + +Some transaction types are not delegatable. If you attempt to grant these permissions to a delegate, the transaction fails with a [result code](../transactions/transaction-results/) such as `tecNO_PERMISSION`. This includes all transaction types that can be used to grant other permissions to different key pairs or accounts. Additionally, all [pseudo-transaction types](/docs/references/protocol/transactions/pseudo-transaction-types/pseudo-transaction-types) are not delegatable since they are not meant to be sent by normal accounts anyway. + +The following permissions cannot be delegated: + +| Transaction Type | Permission Value | +|:--------------------|:-----------------| +| [AccountSet][] | `4` | +| [SetRegularKey][] | `6` | +| [SignerListSet][] | `13` | +| [AccountDelete][] | `22` | +| [LedgerStateFix][] | `54` | +| [DelegateSet][] | `65` | +| [EnableAmendment][] | `101` | +| [SetFee][] | `102` | +| [UNLModify][] | `103` | + +## Granular Permissions +[[Source]](https://github.com/XRPLF/rippled/blob/master/include/xrpl/protocol/detail/permissions.macro "Source") + +Granular Permissions have numeric types of 65537 and up, corresponding to specific names of permissions. Values that are not defined are not allowed. Each granular permission is a subset of a single transaction type's functionality. + +| Numeric Value | Name | Transaction Type | Description | +|:--------------|:-------------------------|:-----------------------|:------------| +| `65537` | `TrustlineAuthorize` | [TrustSet][] | Can [authorize individual trust lines](/docs/concepts/tokens/fungible-tokens/authorized-trust-lines). | +| `65538` | `TrustlineFreeze` | [TrustSet][] | Can [freeze individual trust lines](/docs/concepts/tokens/fungible-tokens/freezes). | +| `65539` | `TrustlineUnfreeze` | [TrustSet][] | Can [unfreeze individual trust lines](/docs/concepts/tokens/fungible-tokens/freezes). | +| `65540` | `AccountDomainSet` | [AccountSet][] | Can set the `Domain` field of the account. | +| `65541` | `AccountEmailHashSet` | [AccountSet][] | Can set the `EmailHash` field of the account. | +| `65542` | `AccountMessageKeySet` | [AccountSet][] | Can set the `MessageKey` field of the account. | +| `65543` | `AccountTransferRateSet` | [AccountSet][] | Can set the [transfer fee of fungible tokens issued by the account](/docs/concepts/tokens/transfer-fees). | +| `65544` | `AccountTickSizeSet` | [AccountSet][] | Can set the [tick size of fungible tokens issued by the account](/docs/concepts/tokens/decentralized-exchange/ticksize). | +| `65545` | `PaymentMint` | [Payment][] | Can send payments that mint new fungible tokens. ***TODO: Or MPTs? What about indirectly?*** | +| `65546` | `PaymentBurn` | [Payment][] | Can send payments that burn fungible tokens. ***TODO: Or MPTs? More clarification needed.*** | +| `65547` | `MPTokenIssuanceLock` | [MPTokenIssuanceSet][] | Can lock the balances of a particular MPT issued by the account. _(Requires the [MPTokensV1 amendment][] {% not-enabled /%}.)_ | +| `65548` | `MPTokenIssuanceUnlock` | [MPTokenIssuanceSet][] | Can unlock the balances of a particular MPT issued by the account. _(Requires the [MPTokensV1 amendment][] {% not-enabled /%}.)_ | + + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md b/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md new file mode 100644 index 0000000000..bb7e28fbaa --- /dev/null +++ b/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md @@ -0,0 +1,52 @@ +--- +seo: + description: A record of which permissions have been granted to another account. +labels: + - Accounts + - Permissions +--- +# Delegate +[[Source]](https://github.com/XRPLF/rippled/blob/1e01cd34f7a216092ed779f291b43324c167167a/include/xrpl/protocol/detail/ledger_entries.macro#L475-L482 "Source") + +A `Delegate` ledger entry stores a set of permissions that an account has delegated to another account. You create a `Delegate` entry by sending a [DelegateSet transaction][]. + +_(Requires the [PermissionDelegation amendment][] {% not-enabled /%}.)_ + +## Example {% $frontmatter.seo.title %} JSON + +```json +TODO +``` + +## {% $frontmatter.seo.title %} Fields + +In addition to the [common fields](../common-fields.md), {% code-page-name /%} entries have the following fields: + +| Field | JSON Type | [Internal Type][] | Required? | Description | +|:--------------------|:---------------------|:------------------|:----------|:-------------| +| `Account` | String - [Address][] | AccountID | Yes | The account delegating permissions to another, also called the _delegating account_. | +| `Authorize` | String - [Address][] | AccountID | Yes | The account receiving permissions, also called the _delegate account_. | +| `Permissions` | Array | Array | Yes | A list of permissions granted, with at least 1 and at most 10 items. Each item in the list is a [Permission Object](#permissions-objects). | +| `OwnerNode` | String - Hexadecimal | UInt64 | Yes | A hint indicating which page of the delegating account's owner directory links to this object, in case the directory consists of multiple pages. +| `PreviousTxnID` | String - Hexadecimal | UInt256 | Yes | The identifying hash of the transaction that most recently modified this object. | +| `PreviousTxnLgrSeq` | Number | UInt32 | Yes |The [index of the ledger][Ledger Index] that contains the transaction that most recently modified this object. | + +### Permissions Objects + +Each item in the `Permissions` array is an inner object with the following nested fields: + +| Field | JSON Type | [Internal Type][] | Required? | Description | +|:------------------|:---------------------|:------------------|:----------|:----------------| +| `PermissionValue` | String | UInt32 | Yes | A permission that has been delegated to this account, which can be either a transaction type or a granular permission. See ***TODO: link*** for a full list. | + +## {% $frontmatter.seo.title %} Flags + +There are no flags defined for {% code-page-name /%} entries. + +## {% $frontmatter.seo.title %} Reserve + +{% code-page-name /%} entries count as one item towards the owner reserve of the delegating account, as long as the entry is in the ledger, regardless of how many permissions are delegating. Removing all permissions deletes the entry and frees up the reserve. + +{% code-page-name /%} entries are not deletion blockers. If the owner (delegating) account is deleted, all such ledger entries are deleted along with them. However, the `Authorize` + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/transactions/common-fields.md b/docs/references/protocol/transactions/common-fields.md index 651d5f3425..a4749bd8be 100644 --- a/docs/references/protocol/transactions/common-fields.md +++ b/docs/references/protocol/transactions/common-fields.md @@ -62,43 +62,14 @@ The [`Paths` field](types/payment.md#paths) of the [Payment transaction][] type ## Delegate -The `Delegate` ledger object stores a set of permissions that an XRPL account has delegated to another account. You create `Delegate` objects using the [`DelegateSet`](./types/delegateset.md) transaction. +If the `Delegate` field is provided, this transaction is being sent by a different account on behalf of the account in the `Account` field. The account in the `Account` is the _delegating account_ and the account in the `Delegate` field is the _delegate_ account. The transaction functions as if it was sent by the delegating account, with the following exceptions: -### Structure +- The signature must be valid for the delegate account. (It can by signed with a master key, regular key, or multi-signing list that is authorized by the delegate.) +- The transaction cost (in the `Fee` field) is paid by the delegate account. -A `Delegate` object has the following fields: +Sending a transaction this way is only possible if the delegating account has granted the appropriate transaction permissions to the delegate account. -| Field Name | Required? | JSON Type | Internal Type | Description | -|------------|-----------|-----------|---------------|-------------| -| `LedgerIndex` | ✔️ | string | Hash256 | The unique ID of the ledger object. | -| `LedgerEntryType` | ✔️ | string | UInt16 | The ledger object's type (`Delegate`) | -| `Account` | ✔️ | string | AccountID | The account that delegates permissions to another account. | -| `Authorize` | ✔️ | string | AccountID | The account to which permissions are delegated. | -| `Permissions` | ✔️ | string | STArray | The transaction permissions that the `Authorize` account has been granted. | -| `OwnerNode` | ✔️ | string | UInt64 | A hint indicating which page of the sender's owner directory links to this object, in case the directory consists of multiple pages. | -| `PreviousTxnID` | ✔️ | string | Hash256 | The identifying hash of the transaction that most recently modified this object. | -| `PreviousTxnLgrSeqNumber`| ✔️ | number | UInt32 |The index of the ledger that contains the transaction that most recently modified this object. | - -### Retrieving Delegate Objects - -You can retrieve `Delegate` ledger objects using the `ledger_entry` RPC method. The unique ID of a `Delegate` object is a hash of the `Account` and `Authorize` fields, combined with the unique space key for Delegate objects. - -### Account Deletion - -A `Delegate` object is not a deletion blocker. This means that deleting an account removes any `Delegate` objects associated with it. - -### Example Delegate JSON - -This sample `Delegate` object shows that the _rISAAC_ account has delegated `TrustLineAuthorize` permission to the _rKYLIE_ account. - -```json -{ - "LedgerEntryType": "Delegate", - "Account": "rISAAC......", - "Authorize": "rKYLIE......", - "Permissions": [{"Permission": {"PermissionValue": "TrustlineAuthorize"}}], -} -``` +_(Requires the [PermissionDelegation amendment][] {% not-enabled /%}.)_ ## Flags Field diff --git a/sidebars.yaml b/sidebars.yaml index 809873e7de..93b168d697 100644 --- a/sidebars.yaml +++ b/sidebars.yaml @@ -350,6 +350,7 @@ - page: docs/references/protocol/ledger-data/ledger-entry-types/bridge.md - page: docs/references/protocol/ledger-data/ledger-entry-types/check.md - page: docs/references/protocol/ledger-data/ledger-entry-types/credential.md + - page: docs/references/protocol/ledger-data/ledger-entry-types/delegate.md - page: docs/references/protocol/ledger-data/ledger-entry-types/depositpreauth.md - page: docs/references/protocol/ledger-data/ledger-entry-types/did.md - page: docs/references/protocol/ledger-data/ledger-entry-types/directorynode.md From 081c2905f5806c4b7cd15c00a45a7d448cfca225 Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Thu, 24 Jul 2025 18:48:40 -0700 Subject: [PATCH 2/7] Add Permission Delegation sample code --- _code-samples/delegate-permissions/README.md | 3 + .../delegate-permissions/js/README.md | 38 ++++++++++ .../js/delegate-permissions.js | 48 ++++++++++++ .../delegate-permissions/js/package.json | 5 ++ .../js/use-delegated-permissions.js | 74 +++++++++++++++++++ 5 files changed, 168 insertions(+) create mode 100644 _code-samples/delegate-permissions/README.md create mode 100644 _code-samples/delegate-permissions/js/README.md create mode 100644 _code-samples/delegate-permissions/js/delegate-permissions.js create mode 100644 _code-samples/delegate-permissions/js/package.json create mode 100644 _code-samples/delegate-permissions/js/use-delegated-permissions.js diff --git a/_code-samples/delegate-permissions/README.md b/_code-samples/delegate-permissions/README.md new file mode 100644 index 0000000000..5c091e927c --- /dev/null +++ b/_code-samples/delegate-permissions/README.md @@ -0,0 +1,3 @@ +# Delegate Permissions + +Delegate permissions to another account, so that the account can send transactions on your behalf. diff --git a/_code-samples/delegate-permissions/js/README.md b/_code-samples/delegate-permissions/js/README.md new file mode 100644 index 0000000000..f8e2ea47e6 --- /dev/null +++ b/_code-samples/delegate-permissions/js/README.md @@ -0,0 +1,38 @@ +# Delegate Permissions (JavaScript) Sample Code + +These code samples demonstrate how to delegate permissions to another account and how to send an a transaction as a delegate, using xrpl.js 4.3 in Node.js. + +## Usage + +1. First, install dependencies. + + ```sh + npm i + ``` + +2. Go to the [XRP Faucet](https://xrpl.org/resources/dev-tools/xrp-faucets) and generate a **Devnet** account to be your delegate account. + +3. Edit `delegate-permisions.js` and change the following line to use the address you got from the faucet: + + ```js + const delegate_address = "r9GAKojMTyexqvy8DXFWYq63Mod5k5wnkT" + ``` + +4. Run `delegate-permissions.js`. + + ```sh + node delegate-permissions.js + ``` + + If it runs successfully, it should output several things including "Delegate successfully set." followed by an [account_objects API method](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account_objects) response showing the delegate permissions. + + Take note of the `account` address in this output. That's the address of the delegating account. + +5. Run `use-delegate-permissions.js` and provide both the delegating account's address (from the previous step's output) and the delegate's secret key (from the devnet faucet earlier). + + If it runs successfully, it should output various things ending in the following: + + ```text + Transaction successful. + Domain is example.com + ``` diff --git a/_code-samples/delegate-permissions/js/delegate-permissions.js b/_code-samples/delegate-permissions/js/delegate-permissions.js new file mode 100644 index 0000000000..e227f967af --- /dev/null +++ b/_code-samples/delegate-permissions/js/delegate-permissions.js @@ -0,0 +1,48 @@ +const xrpl = require('xrpl') + +async function main() { + const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233") + await client.connect() + + console.log("Funding new wallet from faucet...") + const { wallet } = await client.fundWallet() + + // Define the transaction + const delegate_address = "r9GAKojMTyexqvy8DXFWYq63Mod5k5wnkT" + const delegateset = { + "TransactionType": "DelegateSet", + "Account": wallet.address, + "Authorize": delegate_address, + "Permissions": [ + { + "Permission": { + "PermissionValue": "AccountDomainSet" + } + } + ] + } + + // Prepare, sign, and submit the transaction + const prepared = await client.autofill(delegateset) + const signed = wallet.sign(prepared) + const result = await client.submitAndWait(signed.tx_blob) + + // Check transaction results + console.log(result) + if (result.result.meta.TransactionResult === "tesSUCCESS") { + console.log("Delegate successfully set.") + } + + // Confirm presence of Delegate ledger entry using account_objects + response = await client.request({ + "command": "account_objects", + "account": wallet.address, + "type": "delegate", + "ledger_index": "validated" + }) + console.log(JSON.stringify(response, null, 2)) + + client.disconnect() +} + +main() diff --git a/_code-samples/delegate-permissions/js/package.json b/_code-samples/delegate-permissions/js/package.json new file mode 100644 index 0000000000..9a27c14943 --- /dev/null +++ b/_code-samples/delegate-permissions/js/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "xrpl": "^4.3.0" + } +} diff --git a/_code-samples/delegate-permissions/js/use-delegated-permissions.js b/_code-samples/delegate-permissions/js/use-delegated-permissions.js new file mode 100644 index 0000000000..b1fc0077f9 --- /dev/null +++ b/_code-samples/delegate-permissions/js/use-delegated-permissions.js @@ -0,0 +1,74 @@ +const xrpl = require('xrpl') +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}) +const { stringToHex, hexToString } = require('@xrplf/isomorphic/utils') + +// Set delegating account and delegate from user input +readline.question(`Address of delegating account? `, async function(from_address) { + readline.question(`Delegate's secret key? `, async function(secret) { + const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233") + await client.connect() + + const delegate_wallet = xrpl.Wallet.fromSeed(secret) + console.log(`Using delegate address ${delegate_wallet.address}`) + + // Check which permissions the delegate has been granted, if any + response = await client.request({ + "command": "account_objects", + "account": from_address, + "type": "delegate", + "ledger_index": "validated" + }) + let found_match = false + for (delegate_entry of response.result.account_objects) { + if (delegate_entry.Account == from_address && delegate_entry.Authorize == delegate_wallet.address) { + found_match = true + console.log("Delegate has the following permissions:") + for (perm of delegate_entry.Permissions) { + console.log(perm.Permission.PermissionValue) + } + break + } + } + if (!found_match) { + console.warn("Delegate appears not to have any permissions granted by delegating account.") + console.warn("Did you run delegate-permissions.js first with your delegate address?") + return + } + + // Use the AccountDomainSet granular permission to set the "Domain" field + // of the delegating account + const set_domain_example = { + "TransactionType": "AccountSet", + "Account": from_address, + "Delegate": delegate_wallet.address, + "Domain": stringToHex("example.com") + } + + // Prepare, sign, and submit the transaction + const prepared = await client.autofill(set_domain_example) + const signed = delegate_wallet.sign(prepared) + console.log("Submitting transaction:") + console.log(JSON.stringify(signed, null, 2)) + const result = await client.submitAndWait(signed.tx_blob) + + // Check transaction results and disconnect + console.log(result) + if (result.result.meta.TransactionResult === "tesSUCCESS") { + console.log("Transaction successful.") + } + + // Confirm that the account's Domain field has been set as expected + const account_info_resp = await client.request({ + "command": "account_info", + "account": from_address, + "ledger_index": "validated" + }) + const domain_str = hexToString(account_info_resp.result.account_data.Domain) + console.log(`Domain is ${domain_str}`) + + client.disconnect() + }) +}) From a6c24907074e838d0e4d3e7683d7f7396d79aea8 Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Thu, 24 Jul 2025 18:49:07 -0700 Subject: [PATCH 3/7] Fix more permission delegation references --- docs/_snippets/common-links.md | 8 + .../protocol/data-types/permission-values.md | 10 +- .../ledger-entry-types/delegate.md | 10 +- .../protocol/transactions/common-fields.md | 2 +- .../transactions/types/delegateset.md | 154 +++++------------- sidebars.yaml | 1 + 6 files changed, 65 insertions(+), 120 deletions(-) diff --git a/docs/_snippets/common-links.md b/docs/_snippets/common-links.md index 8fc4c24814..59298a687a 100644 --- a/docs/_snippets/common-links.md +++ b/docs/_snippets/common-links.md @@ -101,6 +101,10 @@ [DIDエントリ]: /docs/references/protocol/ledger-data/ledger-entry-types/did.md [DeletableAccounts amendment]: /resources/known-amendments.md#deletableaccounts [DeepFreeze amendment]: /resources/known-amendments.md#deepfreeze +[Delegate ledger entry]: /docs/references/protocol/ledger-data/ledger-entry-types/delegate.md +[DelegateSet]: /docs/references/protocol/transactions/types/delegateset.md +[DelegateSet transaction]: /docs/references/protocol/transactions/types/delegateset.md +[DelegateSet transactions]: /docs/references/protocol/transactions/types/delegateset.md [DepositAuth amendment]: /resources/known-amendments.md#depositauth [DepositPreauth amendment]: /resources/known-amendments.md#depositpreauth [DepositPreauth entry]: /docs/references/protocol/transactions/types/depositpreauth.md @@ -166,6 +170,9 @@ [LedgerStateFix]: /docs/references/protocol/transactions/types/ledgerstatefix.md [LedgerStateFixトランザクション]: /docs/references/protocol/transactions/types/ledgerstatefix.md [Marker]: /docs/references/http-websocket-apis/api-conventions/markers-and-pagination.md +[MPTokenIssuanceSet]: /docs/references/protocol/transactions/types/mptokenissuanceset.md +[MPTokenIssuanceSet transaction]: /docs/references/protocol/transactions/types/mptokenissuanceset.md +[MPTokenIssuanceSet transactions]: /docs/references/protocol/transactions/types/mptokenissuanceset.md [MPTokensV1 amendment]: /resources/known-amendments.md#mptokensv1 [MultiSign amendment]: /resources/known-amendments.md#multisign [MultiSignReserve amendment]: /resources/known-amendments.md#multisignreserve @@ -539,6 +546,7 @@ [ripple_path_findメソッド]: /docs/references/http-websocket-apis/public-api-methods/path-and-order-book-methods/ripple_path_find.md [seconds since the Ripple Epoch]: /docs/references/protocol/data-types/basic-data-types.md#specifying-time [リップルエポックからの秒数]: /docs/references/protocol/data-types/basic-data-types.md#specifying-time +[server_definitions method]: /docs/references/http-websocket-apis/public-api-methods/server-info-methods/server_definitions.md [server_info command]: /docs/references/http-websocket-apis/public-api-methods/server-info-methods/server_info.md [server_info method]: /docs/references/http-websocket-apis/public-api-methods/server-info-methods/server_info.md [server_infoメソッド]: /docs/references/http-websocket-apis/public-api-methods/server-info-methods/server_info.md diff --git a/docs/references/protocol/data-types/permission-values.md b/docs/references/protocol/data-types/permission-values.md index 9d27bf8812..afa5d1c501 100644 --- a/docs/references/protocol/data-types/permission-values.md +++ b/docs/references/protocol/data-types/permission-values.md @@ -22,7 +22,7 @@ The numeric value `0` is reserved for "full permissions", meaning permission to ## Transaction Type Permissions -Transaction Type Permissions have numeric values from 1 to 65536 (216), inclusive. They correspond with known transaction types, except you add 1 when specifying a transaction type as a permission value. For example, the string `"Payment"` corresponds to a `TransactionType` value of `0`, but a `PermissionValue` type of `1`. To grant permissions to make Payment transactions, you can specify either `"PermissionValue": "Payment"` or `"PermissionValue": 1`. +Transaction Type Permissions have numeric values from 1 to 65536 (216), inclusive. They correspond with known transaction types, except you add 1 when specifying a transaction type as a permission value. For example, the string `"Payment"` corresponds to a `TransactionType` value of `0`, but a `PermissionValue` value of `1`. To grant permissions to make Payment transactions, you can specify either `"PermissionValue": "Payment"` or `"PermissionValue": 1`. For a mapping of transaction types known by a server and their corresponding numeric transaction type values, check the `TRANSACTION_TYPES` field in the [server_definitions method][]. @@ -59,10 +59,14 @@ Granular Permissions have numeric types of 65537 and up, corresponding to specif | `65542` | `AccountMessageKeySet` | [AccountSet][] | Can set the `MessageKey` field of the account. | | `65543` | `AccountTransferRateSet` | [AccountSet][] | Can set the [transfer fee of fungible tokens issued by the account](/docs/concepts/tokens/transfer-fees). | | `65544` | `AccountTickSizeSet` | [AccountSet][] | Can set the [tick size of fungible tokens issued by the account](/docs/concepts/tokens/decentralized-exchange/ticksize). | -| `65545` | `PaymentMint` | [Payment][] | Can send payments that mint new fungible tokens. ***TODO: Or MPTs? What about indirectly?*** | -| `65546` | `PaymentBurn` | [Payment][] | Can send payments that burn fungible tokens. ***TODO: Or MPTs? More clarification needed.*** | +| `65545` | `PaymentMint` | [Payment][] | Can send payments that mint new fungible tokens or MPTs. | +| `65546` | `PaymentBurn` | [Payment][] | Can send payments that burn fungible tokens or MPTs. | | `65547` | `MPTokenIssuanceLock` | [MPTokenIssuanceSet][] | Can lock the balances of a particular MPT issued by the account. _(Requires the [MPTokensV1 amendment][] {% not-enabled /%}.)_ | | `65548` | `MPTokenIssuanceUnlock` | [MPTokenIssuanceSet][] | Can unlock the balances of a particular MPT issued by the account. _(Requires the [MPTokensV1 amendment][] {% not-enabled /%}.)_ | +### Limitations to Granular Permissions + +The set of granular permissions is hard-coded. No custom configurations are allowed. For example, you cannot add permissions based on specific currencies. Adding a new granular permission requires an amendment. + {% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md b/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md index bb7e28fbaa..9735e8cb98 100644 --- a/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md +++ b/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md @@ -25,19 +25,19 @@ In addition to the [common fields](../common-fields.md), {% code-page-name /%} e | Field | JSON Type | [Internal Type][] | Required? | Description | |:--------------------|:---------------------|:------------------|:----------|:-------------| | `Account` | String - [Address][] | AccountID | Yes | The account delegating permissions to another, also called the _delegating account_. | -| `Authorize` | String - [Address][] | AccountID | Yes | The account receiving permissions, also called the _delegate account_. | -| `Permissions` | Array | Array | Yes | A list of permissions granted, with at least 1 and at most 10 items. Each item in the list is a [Permission Object](#permissions-objects). | +| `Authorize` | String - [Address][] | AccountID | Yes | The account receiving permissions, also called the _delegate_. | +| `Permissions` | Array | Array | Yes | A list of permissions granted, with at least 1 and at most 10 items. Each item in the list is a [Permission Object](#permission-objects). | | `OwnerNode` | String - Hexadecimal | UInt64 | Yes | A hint indicating which page of the delegating account's owner directory links to this object, in case the directory consists of multiple pages. | `PreviousTxnID` | String - Hexadecimal | UInt256 | Yes | The identifying hash of the transaction that most recently modified this object. | | `PreviousTxnLgrSeq` | Number | UInt32 | Yes |The [index of the ledger][Ledger Index] that contains the transaction that most recently modified this object. | -### Permissions Objects +### Permission Objects -Each item in the `Permissions` array is an inner object with the following nested fields: +Each item in the `Permissions` array is an inner object with the following nested field: | Field | JSON Type | [Internal Type][] | Required? | Description | |:------------------|:---------------------|:------------------|:----------|:----------------| -| `PermissionValue` | String | UInt32 | Yes | A permission that has been delegated to this account, which can be either a transaction type or a granular permission. See ***TODO: link*** for a full list. | +| `PermissionValue` | String or Number | UInt32 | Yes | A permission that has been granted to the delegate, which can be either a transaction type or a granular permission. See [Permission Values](../../data-types/permission-values.md) for a full list. | ## {% $frontmatter.seo.title %} Flags diff --git a/docs/references/protocol/transactions/common-fields.md b/docs/references/protocol/transactions/common-fields.md index a4749bd8be..7ec6bdc52c 100644 --- a/docs/references/protocol/transactions/common-fields.md +++ b/docs/references/protocol/transactions/common-fields.md @@ -67,7 +67,7 @@ If the `Delegate` field is provided, this transaction is being sent by a differe - The signature must be valid for the delegate account. (It can by signed with a master key, regular key, or multi-signing list that is authorized by the delegate.) - The transaction cost (in the `Fee` field) is paid by the delegate account. -Sending a transaction this way is only possible if the delegating account has granted the appropriate transaction permissions to the delegate account. +Sending a transaction this way is only possible if the delegating account has granted the appropriate transaction permissions to the delegate account. For more information, see [Permission Delegation](/docs/concepts/accounts/permission-delegation.md). _(Requires the [PermissionDelegation amendment][] {% not-enabled /%}.)_ diff --git a/docs/references/protocol/transactions/types/delegateset.md b/docs/references/protocol/transactions/types/delegateset.md index e04e46f1f5..c2e8efc295 100644 --- a/docs/references/protocol/transactions/types/delegateset.md +++ b/docs/references/protocol/transactions/types/delegateset.md @@ -7,139 +7,71 @@ labels: - Delegate status: not_enabled --- +# DelegateSet +[[Source]](https://github.com/XRPLF/rippled/blob/master/src/xrpld/app/tx/detail/DelegateSet.cpp "Source") -# DelegateSet -The `DelegateSet` transaction creates, modifies, or deletes a `Delegate` ledger object, thereby granting, changing, or revoking delegated permissions between accounts. +[Delegate permissions](/docs/concepts/accounts/permission-delegation) to another account to send transactions on your behalf. This transaction type can grant, change, or revoke permissions; it creates, modifies, or deletes a [Delegate ledger entry][] accordingly. _(Requires the [PermissionDelegation amendment][] {% not-enabled /%}.)_ -## Example `DelegateSet` JSON - -```json -{ - "TransactionType": "DelegateSet", - "Account": "rDelegatingAccount", - "Authorize": "rDelegatedAccount", - "Permissions": [ - { - "Permission": { - "PermissionValue": "Payment" - } - }, - { - "Permission": { - "PermissionValue": "TrustSet" - } - } - ] -} -``` -## `DelegateSet` Fields - -In addition to the common fields, `DelegateSet` transactions have the following fields: - -| Field | Required? | JSON Type | Internal Type | Description | -|-------|-----------|-----------|---------------|-------------| -| `TransactionType` | Yes | string | UInt16 | The transaction type (DelegateSet). | -| `Account` | Yes | string | AccountID | The address of the account that is delegating the permission(s). | -| `Authorize`| Yes | string | AccountID | The address of the account that is being granted the permission(s). -| `Permissions` | Yes | string | STArray | An array of permission objects. Each object contains a `Permission` object with a `PermissionValue` field specifying the permission being granted. To modify permissions, include all desired permissions in the `Permissions` array. Omitted permissions are revoked. | - -## Updating Permissions - -Sending a new `DelegateSet` with the same `Account` and `Authorize` fields updates and replaces the permission list. - - -## Revoking Permissions - -Permissions are revoked using the `DelegateSet` transaction by specifying only the desired permissions and omitting any previous permissions that are no longer needed. - -### Revoke All Permissions - -To revoke all permissions, send a `DelegateSet` transaction with an empty `Permissions` array: +## Example {% $frontmatter.seo.title %} JSON ```json { - "TransactionType": "DelegateSet", - "Account": "rDelegatingAccount", - "Authorize": "rDelegatedAccount", - "Permissions": [] + "TransactionType": "DelegateSet", + "Account": "rw81qtsfF9rws4RbmYepf5394gp81TQv5Y", + "Authorize": "r9GAKojMTyexqvy8DXFWYq63Mod5k5wnkT", + "Fee": "1", + "Flags": 0, + "LastLedgerSequence": 4747822, + "Permissions": [ + { + "Permission": { + "PermissionValue": "AccountDomainSet" + } + } + ], + "Sequence": 4747802 } ``` -### Revoke Specific Permissions +{% tx-example txid="13E1C2CE2BCECB6223AEA39407169C5429FE9A126825CDD6952E3FF4C728F603" server="devnet" /%} -To revoke specific permissions, include only the permissions that should remain active in the `Permissions` array. +{% raw-partial file="/docs/_snippets/tx-fields-intro.md" /%} -## Security +| Field | Required? | JSON Type | Internal Type | Description | +|:--------------|-----------|----------------------|---------------|-------------| +| `Authorize` | Yes | String - [Address][] | AccountID | The account being granted permissions, also called the _delegate_. | +| `Permissions` | Yes | Array | Array | A list of up to 10 [Permission objects](#permission-objects) each specifying a different permission granted to the delegate. The delegate's permissions are updated to match this set of permissions exactly. To revoke all permissions, use an empty array. | -Giving permissions to other parties requires a high degree of trust, especially when the delegated account can potentially access funds (the `Payment` permission) or charge reserves (any transaction that can create objects). In addition, any account that has permissions for the entire `AccountSet`, `SetRegularKey`, or `SignerListSet` transactions can give themselves any permissions even if this was not originally part of the intention. +If a [Delegate ledger entry][] does not exist to record the granted permissions, this transaction creates one. If it already exists, the transaction updates the set of permissions to match the list in the transaction: any permissions not listed are revoked. If all permissions are revoked, the transaction deletes the Delegate ledger entry. -With granular permissions, however, users can give permissions to other accounts for only parts of transactions without giving them full control. This is especially helpful for managing complex transaction types like `AccountSet`. +{% admonition type="success" name="Tip" %} +If you want to delegate more than 10 permissions, consider using [multi-signing](/docs/concepts/accounts/multi-signing.md) instead. +{% /admonition %} -### Granular Permissions +### Permission Objects -These permissions support control over some smaller portion of a transaction, rather than being able to do all of the functionality that the transaction allows. +Each item in the `Permissions` array is an inner object with the following nested field: -These permissions fall into the gap between the size of the `UInt16` and the `UInt32` (the size of the `SignerListID` field). +| Field | JSON Type | [Internal Type][] | Required? | Description | +|:------------------|:---------------------|:------------------|:----------|:----------------| +| `PermissionValue` | String or Number | UInt32 | Yes | A permission to grant to the delegate, which can be either a transaction type or a granular permission. See [Permission Values](../../data-types/permission-values.md) for a full list. | -| Value | Name | Description | -|-------|-------|-------------| -|`65537`|`TrustlineAuthorize`|Authorize a trustline.| -|`65538`|`TrustlineFreeze`|Freeze a trustline.| -|`65539`|`TrustlineUnfreeze`|Unfreeze a trustline.| -|`65540`|`AccountDomainSet`|Modify the domain of an account.| -|`65541`|`AccountEmailHashSet`|Modify the `EmailHash` of an account.| -|`65542`|`AccountMessageKeySet`|Modify the `MessageKey` of an account.| -|`65543`|`AccountTransferRateSet`|Modify the transfer rate of an account.| -|`65544`|`AccountTickSizeSet`|Modify the tick size of an account.| -|`65545`|`PaymentMint`|Send a payment for a currency where the sending account is the issuer.| -|`65546`|`PaymentBurn`|Send a payment for a currency where the destination account is the issuer.| -|`65547`|`MPTokenIssuanceLock`|Use the `MPTIssuanceSet` transaction to lock (freeze) a holder.| -|`65548`|`MPTokenIssuanceUnlock`|Use the `MPTIssuanceSet` transaction to unlock (unfreeze) a holder.| - -For example, if an account is authorized by `TrustlineFreeze`, it can freeze a trust line by sending a `TrustSet` transaction. However, since it is only authorized to freeze trust lines, it cannot perform other `TrustSet` operations such as unfreezing a trust line, setting No Ripple, applying Deep Freeze, etc. -When an account is authorized by both `TrustlineFreeze` and `TrustSet`, the delegation is still valid, but the granular permission `TrustlineFreeze` has no effect, since the account is already permitted to perform all actions under `TrustSet`. - -For multi-signing a delegation transaction, which is sent by a delegated account, the multi signers must be the delegated account's signers instead of the delegating account's multi signers. - -### Limitations to Granular Permissions - -The set of permissions must be hard-coded. No custom configurations are allowed. For example, you cannot add permissions based on specific currencies. - -In addition, each permission needs to be implemented on its own in the source code. Adding a new permission requires an amendment. - - -## Failure Conditions - -The `DelegateSet` transaction fails if: - -- The `Permissions` array contains more than 10 entries. -- The `Permissions` array contains duplicate entries. -- Any of the specified `PermissionValues` are invalid. -- The `Authorize` account does not exist. - -## State Changes - -A successful `DelegateSet` transaction results in the creation, modification, or deletion of a `Delegate` ledger object. - -- If no `Delegate` object exists for the given `Account` and `Authorize` pair, a new one is created. -- If a `Delegate` object already exists, its `Permissions` field is updated. -- If the `Permissions` array is empty, the `Delegate` object is deleted. ## Error Cases -- If the `Account` is the same as `Authorize`, return `temMALFORMED`. +Besides errors that can occur for all transactions, {% $frontmatter.seo.title %} transactions can result in the following [transaction result codes](../transaction-results/index.md): -- If the `Authorize` account does not exist, return `tecNO_TARGET`. +| Error Code | Description | +|:--------------------------|:------------| +| `tecDIR_FULL` | The sender owns too many items in the ledger already. | +| `tecINSUFFICIENT_RESERVE` | The sender does not have enough XRP to meet the [reserve requirement](/docs/concepts/accounts/reserves.md) of creating a new Delegate ledger entry. | +| `tecNO_PERMISSION` | At least one permission in the `Permissions` list is not delegatable. See [Permission Values](../../data-types/permission-values.md) for which permissions are not delegatable. | +| `tecNO_TARGET` | The account specified in the `Authorize` field does not exist in the ledger. | +| `temARRAY_TOO_LARGE` | The `Permissions` list is too large. It cannot contain more than 10 entries. | +| `temDISABLED` | The [Permission Delegation amendment][] is not enabled. | +| `temMALFORMED` | The transaction was invalid. For example, the `Authorize` account is the same as the sender of the transaction, the `Permissions` list contains duplicate entries, or one of the permissions in the list is not a valid permission. | -- If the `Permissions` list size exceeds 10, return `temARRAY_TOO_LARGE`. - -- If `Permissions` contains a duplicate value, return `temMALFORMED`. - -- If `Permissions` contains transactions that are disabled for delegation, return `tecNO_PERMISSION`. -The transactions disabled for delegation include: `AccountSet`, `RegularKeySet`, `SignerListSet`, `AccountDelete`, `DelegateSet`, `EnableAmendment`, `SetFee`, `UNLModify`, `LedgerStateFix`. - -- If the Account does not have enough balance to meet the reserve requirement, (because `DelegateSet` will create a ledger object `ltDELEGATE`, whose owner is `Account`), return `tecINSUFFICIENT_RESERVE`. {% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/sidebars.yaml b/sidebars.yaml index 93b168d697..a176098a19 100644 --- a/sidebars.yaml +++ b/sidebars.yaml @@ -336,6 +336,7 @@ - page: docs/references/protocol/data-types/base58-encodings.md - page: docs/references/protocol/data-types/currency-formats.md - page: docs/references/protocol/data-types/nftoken.md + - page: docs/references/protocol/data-types/permission-values.md - page: docs/references/protocol/ledger-data/index.md expanded: false items: From 302a8c9a72f2a6ba7936dc8106d2e333a671d309 Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Thu, 24 Jul 2025 19:38:52 -0700 Subject: [PATCH 4/7] Rewrite Permission Delegation concept and further clean up refs --- .../accounts/permission-delegation.md | 107 +++++------------- .../protocol/data-types/permission-values.md | 16 ++- .../ledger-entry-types/delegate.md | 18 ++- .../transactions/types/delegateset.md | 2 +- 4 files changed, 58 insertions(+), 85 deletions(-) diff --git a/docs/concepts/accounts/permission-delegation.md b/docs/concepts/accounts/permission-delegation.md index 0ac735b126..9058e127b9 100644 --- a/docs/concepts/accounts/permission-delegation.md +++ b/docs/concepts/accounts/permission-delegation.md @@ -7,102 +7,53 @@ labels: status: not_enabled --- # Permission Delegation -XRPL accounts can delegate both transaction permissions and granular permissions to other accounts, enhancing flexibility and enabling use cases such as implementing role-based access control. This delegation is managed using the [`DelegateSet`](../../references/protocol/transactions/types/delegateset.md) transaction. -_(Requires the [PermissionDelegation amendment][] {% not-enabled /%})_ +Permission delegation is the function of granting various permissions to another account to send permissions on behalf of your account. This can be used instead of or alongside techniques such as [multi-signing](./multi-signing.md) to enable flexible security paradigms such as role-based access control. -## Assigning Permissions +## Background -You can assign permissions to another account by submitting a `DelegateSet` transaction. +Managing your [cryptographic keys](./cryptographic-keys.md) is one of the more challenging parts of using a blockchain. As part of a defense-in-depth strategy, a secure configuration should limit the damage that can occur if a secret key is compromised. One way to do this is to rotate keys regularly and to keep master keys off of computers that are always connected to the internet and serving user traffic. However, many use cases involve frequently and automatically signing transactions, which typically necessitates having secret keys on an internet-connected server. -```json -tx_json = { - "TransactionType": "DelegateSet", - "Account": "rDelegatingAccount", - "Authorize": "rDelegatedAccount", - "Permissions": [ - { - "Permission": { - "PermissionValue": "Payment" - } - } - ] -} -``` +Permission Delegation can help optimize for these sorts of challenges by granting very limited permissions to separate accounts that can have their keys available online, while keeping the master keys for the main account offline and only using them manually in special cases when rare, important tasks like issuing tokens are necessary. This is especially helpful when using compliance features like [Authorized Trust Lines](../tokens/fungible-tokens/authorized-trust-lines.md) that require a stablecoin issuer to individually approve each user after meeting regulatory requirements like Know Your Customer rules. With a proper configuration, the keys that are used to approve users cannot be used to perform other actions like issuing new tokens or rotating the issuer's key pairs. -| Field | Description | -|-------|-------------| -| `Account` | The address of the account that is delegating the permission(s). | -| `Authorize` | The address of the account that is being granted the permission(s). | -| `Permissions` | An array of permission objects, specifying the permissions to delegate. Each permission is defined within a `Permission` object, using the `PermissionValue` field. See [XLS-74d, Account Permissions] for a complete list of valid `PermissionValues`. | -## Revoking Permissions +## How It Works -Permissions can be revoked using the `DelegateSet` transaction. There are two ways to revoke permissions: +The account on whose behalf transactions are being sent is called the _delegating account_. The account sending the transactions is called the _delegate_. -### Revoke All Permissions +The delegating account first sends a [DelegateSet transaction][] to designate an account as its delegate and to specify which permissions the delegate has. The delegating account can update or revoke the permissions at any time by sending another DelegateSet transaction. -To revoke all permissions previously granted to a delegated account, send a `DelegateSet` transaction with an empty `Permissions` array: +The delegate can send transactions that execute as if they were sent by the delegating account. These transactions specify both the delegating account's information as well as the address of the delegate who is sending the transaction. The delegate can sign these transactions with any of the following: -```json -tx_json = { - "TransactionType": "DelegateSet", - "Account": "rDelegatingAccount", - "Authorize": "rDelegatedAccount", - "Permissions": [] -} -``` +- The delegate's master key pair +- A regular key pair that the delegate has authorized +- A multi-signing list that the delegate has authorized -### Revoke Specific Permissions +The delegate can only send transactions that match the permissions it has. Permissions come in two types: -To revoke specific permissions, send a `DelegateSet` transaction that includes _only_ the permissions that should remain active. Any permissions previously granted to the `Authorize` account that aren't included in the `Permissions` array are revoked. +- **Transaction Type Permissions** - Permission to send transactions of a specific [transaction type](/docs/references/protocol/transactions/types/index.md). Some types cannot be delegated. +- **Granular Permissions** - Permission to send transactions with a specific subset of functionality. -## Sending Transactions with Delegated Permissions +For a complete list of transaction types that can or cannot be delegated as well as a list of granular permissions, see [Permission Values](/docs/references/protocol/data-types/permission-values.md). -When an account has been granted permissions, it can send transactions on behalf of the delegating account using the `Delegate` field. -For example, if `rDelegatingAccount` has delegated the `TrustSet` permission to `rDelegatedAccount`, then `rDelegatedAccount` can submit a `TrustSet` transaction on behalf of `rDelegatingAccount` as follows: +## Comparison with Multi-Signing -```json -transaction_json = { - "TransactionType": "TrustSet", - "Account": "rDelegatingAccount", - "Delegate": "rDelegatedAccount", - "LimitAmount": { - "currency": "USD", - "issuer": "rIssuerAccount", - "value": "1000" - } -} -``` +| | Permission Delegation | Multi-Signing | +|------------------|-----------------------|---------------| +| Transaction cost | Paid by the delegate | Paid by the account that owns the list | +| Permission control | Can only send transactions matching specific permissions granted | Can send any transactions except specific cases that require the master key pair | +| M-of-N permission | Not supported | Configurable quorum and weights with up to 32 signers | +| Unfunded accounts | Delegates must have funded accounts on ledger | Signers can be funded accounts or key pairs with no account on ledger. | +| Key management | Delegate manages their own keys, including multi-signing | Signers can manage their own keys but cannot perform nested multi-signing. | -| Field | Description | -|-------|-------------| -| `Account` | The address of the account that granted permission for the transaction (the _delegating_ account). | -| `Delegate` | The address of the account submitting and signing the transaction. This must be the account that was granted permission (the _delegated_ account). | -The account that sends this transaction is _rDelegatedAccount_, although the Account field is the _rDelegatingAccount_. The secret for this transaction is the _rDelegatedAccount_ secret, which means _rDelegatedAccount_ signs the transaction. +## See Also -## Error Cases - -- If the `PermissionDelegation` feature is not enabled, return `temDISABLED`. - -- If the _rDelegatedAccount_ is not authorized by the _rDelegatingAccount_ for the transaction type or satisfying the granular permissions given by _rDelegatingAccount_, the transaction returns `tecNO_DELEGATE_PERMISSION`. - -- If the _rDelegatedAccount_ does not have enough balance to pay the transaction fee, the transaction returns `terINSUF_FEE_B` . (_rDelegatedAccount_ pays the fee, which is the sender in `Delegate` field, not the `Account` field). - -- If the transaction creates a ledger object, but _rDelegatingAccount_ does not have enough balance to cover the reserve, the transaction returns `tecINSUFFICIENT_RESERVE`. - -- If the key used to sign this account does not match with _rDelegatedAccount_, the transaction returns `rpcBAD_SECRET`. - -- If the `TradingFee` is invalid (non-XRP currency or negative value), return `temBAD_FEE`. - -Any other errors are the same as when the _rDelegatingAccount_ sends transaction for itself. - -{% admonition type="warning" name="Important" %} -* Delegating permissions grants significant control. Ensure you trust the delegated account. -* The account specified in the `Delegate` field is responsible for paying the transaction fee. -* A delegated account can only perform actions that have been explicitly permitted. -{% /admonition %} +- **References:** + - [DelegateSet transaction][] - Grant, update, or revoke permissions to a specific delegate. + - [Delegate ledger entry][] - Data structure on the ledger that records which permissions have been granted. +- **Code Samples:** + - {% repo-link path="_code-samples/delegate-permissions/" %}**Delegate Permissions**{% /repo-link %} {% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/data-types/permission-values.md b/docs/references/protocol/data-types/permission-values.md index afa5d1c501..bfc4f6058b 100644 --- a/docs/references/protocol/data-types/permission-values.md +++ b/docs/references/protocol/data-types/permission-values.md @@ -6,9 +6,8 @@ label: --- # Permission Values -The Permission Delegation amendment {% not-enabled /%} defines permissions that can be granted to other accounts. These permissions fall into three categories: +The Permission Delegation amendment {% not-enabled /%} defines permissions that can be granted to other accounts. These permissions fall into the following categories: -- **Full Permissions** - Permission to send transactions of any type. - **Transaction Type Permissions** - Permission to send transactions with the specified [transaction type](../transactions/types/index.md). - **Granular Permissions** - Permission to send transactions with a specific subset of functionality. @@ -16,13 +15,20 @@ The Permission Delegation amendment {% not-enabled /%} defines permissions that In the [canonical binary format](../binary-format.md) for transactions and ledger data, permission values are stored in a numeric form (specifically, as a 32-bit unsigned integer). However, in JSON they can be specified and returned in string format for convenience, similar to how transaction type names (`TransactionType` fields) work. -When specifying a permission value in JSON, you can use either the numeric value or the string value. When serving data, +When specifying a permission value in JSON, you can use either the numeric value or the string value. When serving data, the server supplies the string value if it is known, and falls back to the numeric value otherwise. -The numeric value `0` is reserved for "full permissions", meaning permission to send transactions of all types. ***TODO: but can you actually delegate full permissions?*** +{% admonition type="warning" name="Caution" %} +Not all client libraries support numeric PermissionValue types. In most cases, you should use the string names of the permissions you want to grant. +{% /admonition %} + +- For *transaction type permissions**, the string is the name of the transaction type exactly (case-sensitive). For example, a permission value of `"PaymentChannelClaim"` grants permission to send [PaymentChannelClaim transactions][]. +- For **granular permissions**, the string is the name of the granular permission (case-sensitive). For example, a permission value of `"TrustlineAuthorize"` grants permission to send TrustSet transactions that authorize trust lines (but not ones that modify other settings such as the trust line limit or freeze status). + +The numeric value `0` is reserved for "full permissions", meaning permission to send transactions of all types. It is technically possible to send a transaction that grants this permission value. However, delegate accounts cannot use full permissions. ## Transaction Type Permissions -Transaction Type Permissions have numeric values from 1 to 65536 (216), inclusive. They correspond with known transaction types, except you add 1 when specifying a transaction type as a permission value. For example, the string `"Payment"` corresponds to a `TransactionType` value of `0`, but a `PermissionValue` value of `1`. To grant permissions to make Payment transactions, you can specify either `"PermissionValue": "Payment"` or `"PermissionValue": 1`. +Transaction Type Permissions have numeric values from 1 to 65536 (that is, 216), inclusive. They correspond with known transaction types, except you add 1 when specifying a transaction type as a permission value. For example, the string `"Payment"` corresponds to a `TransactionType` value of `0`, but a `PermissionValue` value of `1`. To grant permissions to make Payment transactions, you can specify either `"PermissionValue": "Payment"` or `"PermissionValue": 1`. For a mapping of transaction types known by a server and their corresponding numeric transaction type values, check the `TRANSACTION_TYPES` field in the [server_definitions method][]. diff --git a/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md b/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md index 9735e8cb98..3ef3f17828 100644 --- a/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md +++ b/docs/references/protocol/ledger-data/ledger-entry-types/delegate.md @@ -15,7 +15,23 @@ _(Requires the [PermissionDelegation amendment][] {% not-enabled /%}.)_ ## Example {% $frontmatter.seo.title %} JSON ```json -TODO +{ + "Account": "rG8uoRH9uA6AJ6NRj8P4cJG1HNfYcnMPrt", + "Authorize": "r9GAKojMTyexqvy8DXFWYq63Mod5k5wnkT", + "Flags": 0, + "LedgerEntryType": "Delegate", + "OwnerNode": "0", + "Permissions": [ + { + "Permission": { + "PermissionValue": "AccountDomainSet" + } + } + ], + "PreviousTxnID": "08DB1BD6ECFC9E8CBD8D954F4EFF6EFD155A392C5060D767B5621CE18951983A", + "PreviousTxnLgrSeq": 4748731, + "index": "749D3DCDF9F032DDDB8AC49641BACBFDD398C4B6C231C4AB325B7755962329A2" +} ``` ## {% $frontmatter.seo.title %} Fields diff --git a/docs/references/protocol/transactions/types/delegateset.md b/docs/references/protocol/transactions/types/delegateset.md index c2e8efc295..a28af70af2 100644 --- a/docs/references/protocol/transactions/types/delegateset.md +++ b/docs/references/protocol/transactions/types/delegateset.md @@ -8,7 +8,7 @@ labels: status: not_enabled --- # DelegateSet -[[Source]](https://github.com/XRPLF/rippled/blob/master/src/xrpld/app/tx/detail/DelegateSet.cpp "Source") +[[Source]](https://github.com/XRPLF/rippled/blob/1e01cd34f7a216092ed779f291b43324c167167a/src/xrpld/app/tx/detail/DelegateSet.cpp "Source") [Delegate permissions](/docs/concepts/accounts/permission-delegation) to another account to send transactions on your behalf. This transaction type can grant, change, or revoke permissions; it creates, modifies, or deletes a [Delegate ledger entry][] accordingly. From 5d4ed444f4ecb115400addb3644fed47564bea86 Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Fri, 25 Jul 2025 12:46:31 -0700 Subject: [PATCH 5/7] Permission delegation - more small edits --- .../accounts/permission-delegation.md | 21 +++++++++++++++---- .../protocol/data-types/permission-values.md | 12 ++++++++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/concepts/accounts/permission-delegation.md b/docs/concepts/accounts/permission-delegation.md index 9058e127b9..4f8eaadd98 100644 --- a/docs/concepts/accounts/permission-delegation.md +++ b/docs/concepts/accounts/permission-delegation.md @@ -10,6 +10,8 @@ status: not_enabled Permission delegation is the function of granting various permissions to another account to send permissions on behalf of your account. This can be used instead of or alongside techniques such as [multi-signing](./multi-signing.md) to enable flexible security paradigms such as role-based access control. +_(Requires the [PermissionDelegation amendment][] {% not-enabled /%}.)_ + ## Background Managing your [cryptographic keys](./cryptographic-keys.md) is one of the more challenging parts of using a blockchain. As part of a defense-in-depth strategy, a secure configuration should limit the damage that can occur if a secret key is compromised. One way to do this is to rotate keys regularly and to keep master keys off of computers that are always connected to the internet and serving user traffic. However, many use cases involve frequently and automatically signing transactions, which typically necessitates having secret keys on an internet-connected server. @@ -21,9 +23,9 @@ Permission Delegation can help optimize for these sorts of challenges by grantin The account on whose behalf transactions are being sent is called the _delegating account_. The account sending the transactions is called the _delegate_. -The delegating account first sends a [DelegateSet transaction][] to designate an account as its delegate and to specify which permissions the delegate has. The delegating account can update or revoke the permissions at any time by sending another DelegateSet transaction. +The delegating account first sends a [DelegateSet transaction][] to designate an account as its delegate and to specify which permissions the delegate has. The delegating account can update or revoke the permissions at any time by sending another DelegateSet transaction. A delegating account can have more than one delegate, and can grant different sets of permissions to each delegate. -The delegate can send transactions that execute as if they were sent by the delegating account. These transactions specify both the delegating account's information as well as the address of the delegate who is sending the transaction. The delegate can sign these transactions with any of the following: +A delegate can send transactions that execute as if they were sent by the delegating account. These transactions specify both the delegating account's information as well as the address of the delegate who is sending the transaction. The delegate can sign these transactions with any of the following: - The delegate's master key pair - A regular key pair that the delegate has authorized @@ -36,16 +38,27 @@ The delegate can only send transactions that match the permissions it has. Permi For a complete list of transaction types that can or cannot be delegated as well as a list of granular permissions, see [Permission Values](/docs/references/protocol/data-types/permission-values.md). +### Limitations + +The main limiting factor on how many delegates you can have is that you must hold enough XRP to meet the [reserve requirement](./reserves.md). Each delegate's permissions are tracked with a [Delegate ledger entry][], which counts as one item towards the delegating account's owner reserve. + +Each delegate can be granted up to 10 permissions. + +Some permissions cannot be delegated, especially permissions that would allow the delegate to change cryptographic keys or grant additional permissions. + +The available set of granular permissions is hard-coded, and the permissions cannot be customized. For example, you cannot grant permission to send only certain currencies and not others. ## Comparison with Multi-Signing +Permission delegation is similar to multi-signing in that it allows other key pairs to sign transactions that "come from" your account. However, there are key differences in functionality between the two, as summarized in the following table: + | | Permission Delegation | Multi-Signing | |------------------|-----------------------|---------------| | Transaction cost | Paid by the delegate | Paid by the account that owns the list | -| Permission control | Can only send transactions matching specific permissions granted | Can send any transactions except specific cases that require the master key pair | +| Permission control | Can only send transactions matching specific permissions granted | Can send any transactions except [specific cases that require the master key pair](./cryptographic-keys.md#special-permissions) | | M-of-N permission | Not supported | Configurable quorum and weights with up to 32 signers | | Unfunded accounts | Delegates must have funded accounts on ledger | Signers can be funded accounts or key pairs with no account on ledger. | -| Key management | Delegate manages their own keys, including multi-signing | Signers can manage their own keys but cannot perform nested multi-signing. | +| Key management | Delegate manages their own keys, including multi-signing | Signers with funded accounts can manage their own keys but cannot perform nested multi-signing. | ## See Also diff --git a/docs/references/protocol/data-types/permission-values.md b/docs/references/protocol/data-types/permission-values.md index bfc4f6058b..ead5980292 100644 --- a/docs/references/protocol/data-types/permission-values.md +++ b/docs/references/protocol/data-types/permission-values.md @@ -6,11 +6,13 @@ label: --- # Permission Values -The Permission Delegation amendment {% not-enabled /%} defines permissions that can be granted to other accounts. These permissions fall into the following categories: +[Permission delegation](/docs/concepts/accounts/permission-delegation.md) defines permissions that can be granted to other accounts. These permissions fall into the following categories: - **Transaction Type Permissions** - Permission to send transactions with the specified [transaction type](../transactions/types/index.md). - **Granular Permissions** - Permission to send transactions with a specific subset of functionality. +_(Requires the [PermissionDelegation amendment][] {% not-enabled /%}.)_ + ## Numeric and String Values In the [canonical binary format](../binary-format.md) for transactions and ledger data, permission values are stored in a numeric form (specifically, as a 32-bit unsigned integer). However, in JSON they can be specified and returned in string format for convenience, similar to how transaction type names (`TransactionType` fields) work. @@ -21,10 +23,10 @@ When specifying a permission value in JSON, you can use either the numeric value Not all client libraries support numeric PermissionValue types. In most cases, you should use the string names of the permissions you want to grant. {% /admonition %} -- For *transaction type permissions**, the string is the name of the transaction type exactly (case-sensitive). For example, a permission value of `"PaymentChannelClaim"` grants permission to send [PaymentChannelClaim transactions][]. +- For **transaction type permissions**, the string is the name of the transaction type exactly (case-sensitive). For example, a permission value of `"PaymentChannelClaim"` grants permission to send [PaymentChannelClaim transactions][]. - For **granular permissions**, the string is the name of the granular permission (case-sensitive). For example, a permission value of `"TrustlineAuthorize"` grants permission to send TrustSet transactions that authorize trust lines (but not ones that modify other settings such as the trust line limit or freeze status). -The numeric value `0` is reserved for "full permissions", meaning permission to send transactions of all types. It is technically possible to send a transaction that grants this permission value. However, delegate accounts cannot use full permissions. +The numeric value `0` is reserved for "full permissions", meaning permission to send transactions of all types, but it is not possible to delegate full permissions. ## Transaction Type Permissions @@ -50,6 +52,10 @@ The following permissions cannot be delegated: | [SetFee][] | `102` | | [UNLModify][] | `103` | +{% admonition type="warning" name="Known Issue" %} +With only the PermissionDelegation amendment, it's possible to assign permissions for transaction types that are reserved, unassigned, or part of amendments that are not currently enabled; it's also possible to assign PermissionValue `0` for full permissions. However, these values do not actually grant any permissions. This is a bug, and a future amendment will prevent assigning values outside of currently-enabled, delegatable transaction types or known granular permissions. +{% /admonition %} + ## Granular Permissions [[Source]](https://github.com/XRPLF/rippled/blob/master/include/xrpl/protocol/detail/permissions.macro "Source") From 4103095b39d2d0abafc0cbe80065e87f8043027f Mon Sep 17 00:00:00 2001 From: Rome Reginelli Date: Tue, 5 Aug 2025 10:43:48 -0700 Subject: [PATCH 6/7] Apply suggestions from @oeggert review Co-authored-by: oeggert <117319296+oeggert@users.noreply.github.com> --- _code-samples/delegate-permissions/js/README.md | 6 +++--- .../delegate-permissions/js/delegate-permissions.js | 2 +- docs/references/protocol/data-types/permission-values.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/_code-samples/delegate-permissions/js/README.md b/_code-samples/delegate-permissions/js/README.md index f8e2ea47e6..4259d88f46 100644 --- a/_code-samples/delegate-permissions/js/README.md +++ b/_code-samples/delegate-permissions/js/README.md @@ -4,7 +4,7 @@ These code samples demonstrate how to delegate permissions to another account an ## Usage -1. First, install dependencies. +1. Install dependencies. ```sh npm i @@ -26,9 +26,9 @@ These code samples demonstrate how to delegate permissions to another account an If it runs successfully, it should output several things including "Delegate successfully set." followed by an [account_objects API method](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account_objects) response showing the delegate permissions. - Take note of the `account` address in this output. That's the address of the delegating account. + Take note of the `account` address in this output. That's the address of the delegator. -5. Run `use-delegate-permissions.js` and provide both the delegating account's address (from the previous step's output) and the delegate's secret key (from the devnet faucet earlier). +5. Run `use-delegate-permissions.js` and provide both the delegator's address (from the previous step's output) and the delegate's secret key (from the devnet faucet earlier). If it runs successfully, it should output various things ending in the following: diff --git a/_code-samples/delegate-permissions/js/delegate-permissions.js b/_code-samples/delegate-permissions/js/delegate-permissions.js index e227f967af..bf4ea1d155 100644 --- a/_code-samples/delegate-permissions/js/delegate-permissions.js +++ b/_code-samples/delegate-permissions/js/delegate-permissions.js @@ -11,7 +11,7 @@ async function main() { const delegate_address = "r9GAKojMTyexqvy8DXFWYq63Mod5k5wnkT" const delegateset = { "TransactionType": "DelegateSet", - "Account": wallet.address, + "Account": wallet.address, // Delegator address "Authorize": delegate_address, "Permissions": [ { diff --git a/docs/references/protocol/data-types/permission-values.md b/docs/references/protocol/data-types/permission-values.md index ead5980292..02b5306ea1 100644 --- a/docs/references/protocol/data-types/permission-values.md +++ b/docs/references/protocol/data-types/permission-values.md @@ -36,7 +36,7 @@ For a mapping of transaction types known by a server and their corresponding num ### List of Non-Delegatable Permissions -Some transaction types are not delegatable. If you attempt to grant these permissions to a delegate, the transaction fails with a [result code](../transactions/transaction-results/) such as `tecNO_PERMISSION`. This includes all transaction types that can be used to grant other permissions to different key pairs or accounts. Additionally, all [pseudo-transaction types](/docs/references/protocol/transactions/pseudo-transaction-types/pseudo-transaction-types) are not delegatable since they are not meant to be sent by normal accounts anyway. +Some transaction types can't be delegated. If you attempt to grant these permissions to a delegate, the transaction fails with a [result code](../transactions/transaction-results/) such as `tecNO_PERMISSION`. This includes all transaction types that can be used to grant other permissions to different key pairs or accounts. Additionally, all [pseudo-transaction types](/docs/references/protocol/transactions/pseudo-transaction-types/pseudo-transaction-types) can't be delegated since they can't be sent by normal accounts anyway. The following permissions cannot be delegated: From b7fe46fe19ef5e9ed4945438d496194bd13dd837 Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Tue, 5 Aug 2025 11:31:51 -0700 Subject: [PATCH 7/7] More Permission Delegation edits per review --- .../delegate-permissions/js/README.md | 14 ++----- .../js/delegate-permissions.js | 25 +++++++----- .../js/use-delegated-permissions.js | 38 +++++++++++-------- .../accounts/permission-delegation.md | 15 ++++---- 4 files changed, 49 insertions(+), 43 deletions(-) diff --git a/_code-samples/delegate-permissions/js/README.md b/_code-samples/delegate-permissions/js/README.md index 4259d88f46..785166a81c 100644 --- a/_code-samples/delegate-permissions/js/README.md +++ b/_code-samples/delegate-permissions/js/README.md @@ -10,15 +10,7 @@ These code samples demonstrate how to delegate permissions to another account an npm i ``` -2. Go to the [XRP Faucet](https://xrpl.org/resources/dev-tools/xrp-faucets) and generate a **Devnet** account to be your delegate account. - -3. Edit `delegate-permisions.js` and change the following line to use the address you got from the faucet: - - ```js - const delegate_address = "r9GAKojMTyexqvy8DXFWYq63Mod5k5wnkT" - ``` - -4. Run `delegate-permissions.js`. +2. Run `delegate-permisions.js`. ```sh node delegate-permissions.js @@ -26,9 +18,9 @@ These code samples demonstrate how to delegate permissions to another account an If it runs successfully, it should output several things including "Delegate successfully set." followed by an [account_objects API method](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account_objects) response showing the delegate permissions. - Take note of the `account` address in this output. That's the address of the delegator. + Take note of the **Delegator address** and **Delegate seed** from the output. -5. Run `use-delegate-permissions.js` and provide both the delegator's address (from the previous step's output) and the delegate's secret key (from the devnet faucet earlier). +3. Run `use-delegate-permissions.js` and provide both the delegator's address and the delegate's secret key that were output in the previous step. If it runs successfully, it should output various things ending in the following: diff --git a/_code-samples/delegate-permissions/js/delegate-permissions.js b/_code-samples/delegate-permissions/js/delegate-permissions.js index bf4ea1d155..4059c8ec67 100644 --- a/_code-samples/delegate-permissions/js/delegate-permissions.js +++ b/_code-samples/delegate-permissions/js/delegate-permissions.js @@ -4,15 +4,21 @@ async function main() { const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233") await client.connect() - console.log("Funding new wallet from faucet...") - const { wallet } = await client.fundWallet() + console.log("Funding new wallets from faucet...") + const delegator_wallet = (await client.fundWallet()).wallet + console.log("Delegator account:") + console.log(" Address:", delegator_wallet.address) + const delegate_wallet = (await client.fundWallet()).wallet + console.log("Delegate account:") + console.log(" Address:", delegate_wallet.address) + console.log(" Seed:", delegate_wallet.seed) + console.log("Please note these values for later.") // Define the transaction - const delegate_address = "r9GAKojMTyexqvy8DXFWYq63Mod5k5wnkT" const delegateset = { "TransactionType": "DelegateSet", - "Account": wallet.address, // Delegator address - "Authorize": delegate_address, + "Account": delegator_wallet.address, + "Authorize": delegate_wallet.address, "Permissions": [ { "Permission": { @@ -23,9 +29,10 @@ async function main() { } // Prepare, sign, and submit the transaction - const prepared = await client.autofill(delegateset) - const signed = wallet.sign(prepared) - const result = await client.submitAndWait(signed.tx_blob) + const result = await client.submitAndWait(delegateset, { + wallet: delegator_wallet, + autofill: true + }) // Check transaction results console.log(result) @@ -36,7 +43,7 @@ async function main() { // Confirm presence of Delegate ledger entry using account_objects response = await client.request({ "command": "account_objects", - "account": wallet.address, + "account": delegator_wallet.address, "type": "delegate", "ledger_index": "validated" }) diff --git a/_code-samples/delegate-permissions/js/use-delegated-permissions.js b/_code-samples/delegate-permissions/js/use-delegated-permissions.js index b1fc0077f9..37fd7afadf 100644 --- a/_code-samples/delegate-permissions/js/use-delegated-permissions.js +++ b/_code-samples/delegate-permissions/js/use-delegated-permissions.js @@ -5,9 +5,9 @@ const readline = require('readline').createInterface({ }) const { stringToHex, hexToString } = require('@xrplf/isomorphic/utils') -// Set delegating account and delegate from user input -readline.question(`Address of delegating account? `, async function(from_address) { - readline.question(`Delegate's secret key? `, async function(secret) { +// Get delegator and delegate accounts from user input +readline.question(`Delegator's address? `, async function(delegator_address) { + readline.question(`Delegate's seed? `, async function(secret) { const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233") await client.connect() @@ -17,13 +17,15 @@ readline.question(`Address of delegating account? `, async function(from_address // Check which permissions the delegate has been granted, if any response = await client.request({ "command": "account_objects", - "account": from_address, + "account": delegator_address, "type": "delegate", "ledger_index": "validated" }) let found_match = false for (delegate_entry of response.result.account_objects) { - if (delegate_entry.Account == from_address && delegate_entry.Authorize == delegate_wallet.address) { + if (delegate_entry.Account == delegator_address && + delegate_entry.Authorize == delegate_wallet.address) { + found_match = true console.log("Delegate has the following permissions:") for (perm of delegate_entry.Permissions) { @@ -33,26 +35,29 @@ readline.question(`Address of delegating account? `, async function(from_address } } if (!found_match) { - console.warn("Delegate appears not to have any permissions granted by delegating account.") - console.warn("Did you run delegate-permissions.js first with your delegate address?") + console.warn("Delegate appears not to have any permissions granted"+ + " by the delegator.") + console.warn("Make sure you ran delegate-permissions.js and input the"+ + " correct delegate/delegator values to this script.") return } // Use the AccountDomainSet granular permission to set the "Domain" field - // of the delegating account + // of the delegator const set_domain_example = { "TransactionType": "AccountSet", - "Account": from_address, + "Account": delegator_address, "Delegate": delegate_wallet.address, "Domain": stringToHex("example.com") } // Prepare, sign, and submit the transaction - const prepared = await client.autofill(set_domain_example) - const signed = delegate_wallet.sign(prepared) console.log("Submitting transaction:") - console.log(JSON.stringify(signed, null, 2)) - const result = await client.submitAndWait(signed.tx_blob) + console.log(set_domain_example) + const result = await client.submitAndWait(set_domain_example, { + wallet: delegate_wallet, + autofill: true + }) // Check transaction results and disconnect console.log(result) @@ -61,14 +66,15 @@ readline.question(`Address of delegating account? `, async function(from_address } // Confirm that the account's Domain field has been set as expected - const account_info_resp = await client.request({ + const acct_info_resp = await client.request({ "command": "account_info", - "account": from_address, + "account": delegator_address, "ledger_index": "validated" }) - const domain_str = hexToString(account_info_resp.result.account_data.Domain) + const domain_str = hexToString(acct_info_resp.result.account_data.Domain) console.log(`Domain is ${domain_str}`) client.disconnect() + readline.close() }) }) diff --git a/docs/concepts/accounts/permission-delegation.md b/docs/concepts/accounts/permission-delegation.md index 4f8eaadd98..d2181b16d3 100644 --- a/docs/concepts/accounts/permission-delegation.md +++ b/docs/concepts/accounts/permission-delegation.md @@ -8,24 +8,25 @@ status: not_enabled --- # Permission Delegation -Permission delegation is the function of granting various permissions to another account to send permissions on behalf of your account. This can be used instead of or alongside techniques such as [multi-signing](./multi-signing.md) to enable flexible security paradigms such as role-based access control. +Permission delegation is the function of granting various permissions to another account to send permissions on behalf of your account. You can use permission delegation to enable flexible security paradigms such as role-based access control, instead of or alongside techniques such as [multi-signing](./multi-signing.md). _(Requires the [PermissionDelegation amendment][] {% not-enabled /%}.)_ + ## Background -Managing your [cryptographic keys](./cryptographic-keys.md) is one of the more challenging parts of using a blockchain. As part of a defense-in-depth strategy, a secure configuration should limit the damage that can occur if a secret key is compromised. One way to do this is to rotate keys regularly and to keep master keys off of computers that are always connected to the internet and serving user traffic. However, many use cases involve frequently and automatically signing transactions, which typically necessitates having secret keys on an internet-connected server. +Managing your [cryptographic keys](./cryptographic-keys.md) is one of the more challenging parts of using a blockchain. As part of a defense-in-depth strategy, a secure configuration should limit the damage that can occur if a secret key is compromised. One way to do this is to rotate keys regularly and to keep master keys off of computers that are always connected to the internet and serving user traffic. However, many use cases involve frequently and automatically signing transactions, which typically requires having secret keys on an internet-connected server. -Permission Delegation can help optimize for these sorts of challenges by granting very limited permissions to separate accounts that can have their keys available online, while keeping the master keys for the main account offline and only using them manually in special cases when rare, important tasks like issuing tokens are necessary. This is especially helpful when using compliance features like [Authorized Trust Lines](../tokens/fungible-tokens/authorized-trust-lines.md) that require a stablecoin issuer to individually approve each user after meeting regulatory requirements like Know Your Customer rules. With a proper configuration, the keys that are used to approve users cannot be used to perform other actions like issuing new tokens or rotating the issuer's key pairs. +Permission Delegation can reduce this problem by granting very limited permissions to separate accounts that have their keys available online for day-to-day tasks. Meanwhile, the keys with full control over the account can be kept offline, so that you only use them for special tasks, like issuing tokens. This is especially helpful when using compliance features like [Authorized Trust Lines](../tokens/fungible-tokens/authorized-trust-lines.md) that require a stablecoin issuer to individually approve each user after meeting regulatory requirements like Know Your Customer rules. With a proper configuration, you can minimize the consequences of a delegate's keys being compromized. ## How It Works -The account on whose behalf transactions are being sent is called the _delegating account_. The account sending the transactions is called the _delegate_. +The account on whose behalf transactions are being sent is called the _delegator_. The account sending the transactions is called the _delegate_. -The delegating account first sends a [DelegateSet transaction][] to designate an account as its delegate and to specify which permissions the delegate has. The delegating account can update or revoke the permissions at any time by sending another DelegateSet transaction. A delegating account can have more than one delegate, and can grant different sets of permissions to each delegate. +The delegator first sends a [DelegateSet transaction][] to designate an account as its delegate and to specify which permissions the delegate has. The delegator can update or revoke the permissions at any time by sending another DelegateSet transaction. A delegator can have more than one delegate, and can grant different sets of permissions to each delegate. -A delegate can send transactions that execute as if they were sent by the delegating account. These transactions specify both the delegating account's information as well as the address of the delegate who is sending the transaction. The delegate can sign these transactions with any of the following: +A delegate can send transactions that execute as if they were sent by the delegator. These transactions specify both the delegator's information as well as the address of the delegate who is sending the transaction. The delegate can sign these transactions with any of the following: - The delegate's master key pair - A regular key pair that the delegate has authorized @@ -40,7 +41,7 @@ For a complete list of transaction types that can or cannot be delegated as well ### Limitations -The main limiting factor on how many delegates you can have is that you must hold enough XRP to meet the [reserve requirement](./reserves.md). Each delegate's permissions are tracked with a [Delegate ledger entry][], which counts as one item towards the delegating account's owner reserve. +The main limiting factor on how many delegates you can have is that you must hold enough XRP to meet the [reserve requirement](./reserves.md). Each delegate's permissions are tracked with a [Delegate ledger entry][], which counts as one item towards the delegator's owner reserve. Each delegate can be granted up to 10 permissions.