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