From ae815e6b8787acb0ceac15390c4be656654e9b47 Mon Sep 17 00:00:00 2001 From: Maria Shodunke Date: Fri, 23 Jan 2026 15:30:47 +0000 Subject: [PATCH] Updated Tutorials to use Devnet - Updates tutorial network to Devnet - Adds setup script to help create Devnet data instead of using hardcoded values --- .gitignore | 1 + _code-samples/vaults/js/createVault.js | 32 ++- _code-samples/vaults/js/deposit.js | 30 +- _code-samples/vaults/js/package.json | 2 +- _code-samples/vaults/js/vaultSetup.js | 262 ++++++++++++++++++ _code-samples/vaults/js/withdraw.js | 25 +- .../tutorials/create-a-single-asset-vault.md | 7 +- .../tutorials/deposit-into-a-vault.md | 13 +- .../tutorials/withdraw-from-a-vault.md | 8 +- 9 files changed, 334 insertions(+), 46 deletions(-) create mode 100644 _code-samples/vaults/js/vaultSetup.js diff --git a/.gitignore b/.gitignore index 81377dd1..69e5fba1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules .DS_Store _code-samples/*/js/package-lock.json +_code-samples/*/js/*[Ss]etup.json diff --git a/_code-samples/vaults/js/createVault.js b/_code-samples/vaults/js/createVault.js index ea3208c4..94c791bb 100644 --- a/_code-samples/vaults/js/createVault.js +++ b/_code-samples/vaults/js/createVault.js @@ -1,24 +1,26 @@ import xrpl from "xrpl" +import { execSync } from "child_process" +import fs from "fs" -// Connect to the network ---------------------- -// This is a lending protocol-specific devnet. This network may be taken -// offline once the lending protocol is live on mainnet. -const client = new xrpl.Client("wss://lend.devnet.rippletest.net:51233") -await client.connect() +// Auto-run setup if needed +if (!fs.existsSync("vaultSetup.json")) { + console.log(`\n=== Vault setup data doesn't exist. Running setup script... ===\n`) + execSync("node vaultSetup.js", { stdio: "inherit" }) +} -// Use the Lending Devnet faucet -const faucetHost = "lend-faucet.devnet.rippletest.net" -const faucetPath = "/accounts" +// Load setup data +const setupData = JSON.parse(fs.readFileSync("vaultSetup.json", "utf8")) -// Create and fund vault owner account -const { wallet: vaultOwner } = await client.fundWallet(null, { faucetHost, faucetPath }) +// Connect to the network +const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233") +await client.connect() -// A pre-existing Vault asset, created for this tutorial. You can specify your own Vault asset. -const mptIssuanceId = "0003E3B486D3DACD8BB468AB33793B9626BD894A92AB3AB4" +// Create and fund vault owner account +const { wallet: vaultOwner } = await client.fundWallet() -// A pre-existing Permissioned Domain ID, created for this tutorial. You can specify your own Domain ID. -// NOTE: You don't need this if you want to create a public vault. -const domainId = "3BB81D0D164456A2D74720F63FD923F16DE08FB3223D3ED103D09F525A8D69D1" +// You can replace these values with your own +const mptIssuanceId = setupData.mptIssuanceId +const domainId = setupData.domainId console.log(`Vault owner address: ${vaultOwner.address}`) console.log(`MPT issuance ID: ${mptIssuanceId}`) diff --git a/_code-samples/vaults/js/deposit.js b/_code-samples/vaults/js/deposit.js index 9fa6723f..c91c4965 100644 --- a/_code-samples/vaults/js/deposit.js +++ b/_code-samples/vaults/js/deposit.js @@ -5,21 +5,27 @@ // values with your own. import xrpl from "xrpl" +import { execSync } from "child_process" +import fs from "fs" -// Connect to the network ---------------------- -// This is a lending protocol-specific devnet. This network may be taken -// offline once the lending protocol is live on mainnet. -const client = new xrpl.Client("wss://lend.devnet.rippletest.net:51233") -await client.connect() +// Auto-run setup if needed +if (!fs.existsSync("vaultSetup.json")) { + console.log(`\n=== Vault setup data doesn't exist. Running setup script... ===\n`) + execSync("node vaultSetup.js", { stdio: "inherit" }) +} -const depositor = xrpl.Wallet.fromSeed("sEdVSq9Zsv8vQwfivTk37bWxrvpnruf") +// Load setup data +const setupData = JSON.parse(fs.readFileSync("vaultSetup.json", "utf8")) + +// Connect to the network +const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233") +await client.connect() -// The ID of the vault to deposit into -const vaultID = "6AC4EC2D775C6275D314996D6ECDD16DCB9382A29FDB769951C42192FCED76EF" -// The ID of the vault's asset (MPT Issuance) -const assetMPTIssuanceId = "0003E3B486D3DACD8BB468AB33793B9626BD894A92AB3AB4" -// The ID of the vault's share (MPT Issuance) -const shareMPTIssuanceId = "0000000152E7CD364F869E832EDB806C4A7AD8B3D0C151C5" +// You can replace these values with your own +const depositor = xrpl.Wallet.fromSeed(setupData.depositor.seed) +const vaultID = setupData.vaultID +const assetMPTIssuanceId = setupData.mptIssuanceId +const shareMPTIssuanceId = setupData.vaultShareMPTIssuanceId console.log(`Depositor address: ${depositor.address}`) console.log(`Vault ID: ${vaultID}`) diff --git a/_code-samples/vaults/js/package.json b/_code-samples/vaults/js/package.json index 31726e30..528ddea3 100644 --- a/_code-samples/vaults/js/package.json +++ b/_code-samples/vaults/js/package.json @@ -2,7 +2,7 @@ "name": "vault-examples", "description": "Example code for creating and managing vaults", "dependencies": { - "xrpl": "^4.4.3" + "xrpl": "^4.5.0" }, "type": "module" } diff --git a/_code-samples/vaults/js/vaultSetup.js b/_code-samples/vaults/js/vaultSetup.js new file mode 100644 index 00000000..da5ec5fd --- /dev/null +++ b/_code-samples/vaults/js/vaultSetup.js @@ -0,0 +1,262 @@ +import xrpl from 'xrpl' +import fs from 'fs' + +// Setup script for vault tutorials + +process.stdout.write('Setting up tutorial: 0/5\r') + +const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233') +await client.connect() + +// Create and fund all wallets +const [ + { wallet: mptIssuer }, + { wallet: domainOwner }, + { wallet: depositor }, + { wallet: vaultOwner } +] = await Promise.all([ + client.fundWallet(), + client.fundWallet(), + client.fundWallet(), + client.fundWallet() +]) + +// Step 1: Create MPT issuance +process.stdout.write('Setting up tutorial: 1/5\r') + +const mptCreateResult = await client.submitAndWait( + { + TransactionType: 'MPTokenIssuanceCreate', + Account: mptIssuer.address, + Flags: + xrpl.MPTokenIssuanceCreateFlags.tfMPTCanTransfer | + xrpl.MPTokenIssuanceCreateFlags.tfMPTCanLock, + AssetScale: 2, + TransferFee: 0, + MaximumAmount: '1000000000000', + MPTokenMetadata: xrpl.encodeMPTokenMetadata({ + ticker: 'USTST', + name: 'USTST Stablecoin', + desc: 'A test stablecoin token', + icon: 'example.org/ustst-icon.png', + asset_class: 'rwa', + asset_subclass: 'stablecoin', + issuer_name: 'Test Stablecoin Inc', + uris: [ + { + uri: 'example.org/ustst', + category: 'website', + title: 'USTST Official Website' + }, + { + uri: 'example.org/ustst/reserves', + category: 'attestation', + title: 'Reserve Attestation Reports' + }, + { + uri: 'example.org/ustst/docs', + category: 'docs', + title: 'USTST Documentation' + } + ], + additional_info: { + backing: 'USD', + reserve_ratio: '1:1' + } + }) + }, + { wallet: mptIssuer, autofill: true } +) + +const mptIssuanceId = mptCreateResult.result.meta.mpt_issuance_id + +// Step 2: Create Permissioned Domain +process.stdout.write('Setting up tutorial: 2/5\r') + +const credType = 'VaultAccess' +const domainResult = await client.submitAndWait( + { + TransactionType: 'PermissionedDomainSet', + Account: domainOwner.address, + AcceptedCredentials: [ + { + Credential: { + Issuer: domainOwner.address, + CredentialType: xrpl.convertStringToHex(credType) + } + } + ] + }, + { wallet: domainOwner, autofill: true } +) + +const domainId = domainResult.result.meta.AffectedNodes.find( + (node) => node.CreatedNode?.LedgerEntryType === 'PermissionedDomain' +).CreatedNode.LedgerIndex + +// Step 3: Create depositor account with credentials and MPT balance +process.stdout.write('Setting up tutorial: 3/5\r') + +await Promise.all([ + client.submitAndWait( + { + TransactionType: 'CredentialCreate', + Account: domainOwner.address, + Subject: depositor.address, + CredentialType: xrpl.convertStringToHex(credType) + }, + { wallet: domainOwner, autofill: true } + ), + client.submitAndWait( + { + TransactionType: 'Batch', + Account: depositor.address, + Flags: xrpl.BatchFlags.tfAllOrNothing, + RawTransactions: [ + { + RawTransaction: { + TransactionType: 'CredentialAccept', + Account: depositor.address, + Issuer: domainOwner.address, + CredentialType: xrpl.convertStringToHex(credType), + Flags: xrpl.GlobalFlags.tfInnerBatchTxn + } + }, + { + RawTransaction: { + TransactionType: 'MPTokenAuthorize', + Account: depositor.address, + MPTokenIssuanceID: mptIssuanceId, + Flags: xrpl.GlobalFlags.tfInnerBatchTxn + } + } + ] + }, + { wallet: depositor, autofill: true } + ) +]) + +process.stdout.write('Setting up tutorial: 4/6\r') + +const paymentResult = await client.submitAndWait( + { + TransactionType: 'Payment', + Account: mptIssuer.address, + Destination: depositor.address, + Amount: { + mpt_issuance_id: mptIssuanceId, + value: '10000' + } + }, + { wallet: mptIssuer, autofill: true } +) + +if (paymentResult.result.meta.TransactionResult !== 'tesSUCCESS') { + console.error('\nPayment failed:', paymentResult.result.meta.TransactionResult) + await client.disconnect() + process.exit(1) +} + +// Step 5: Create a vault for deposit/withdraw examples +process.stdout.write('Setting up tutorial: 5/6\r') + +const vaultCreateResult = await client.submitAndWait( + { + TransactionType: 'VaultCreate', + Account: vaultOwner.address, + Asset: { + mpt_issuance_id: mptIssuanceId + }, + Flags: xrpl.VaultCreateFlags.tfVaultPrivate, + DomainID: domainId, + Data: xrpl.convertStringToHex('Private vault for tutorials'), + MPTokenMetadata: xrpl.encodeMPTokenMetadata({ + ticker: 'SHARE1', + name: 'Vault Shares', + desc: 'Proportional ownership shares of the vault', + icon: 'example.com/vault-shares-icon.png', + asset_class: 'defi', + issuer_name: 'Vault Owner', + uris: [ + { + uri: 'example.com/asset', + category: 'website', + title: 'Asset Website' + }, + { + uri: 'example.com/docs', + category: 'docs', + title: 'Docs' + } + ], + additional_info: { + example_info: 'test' + } + }), + AssetsMaximum: '0', + WithdrawalPolicy: + xrpl.VaultWithdrawalPolicy.vaultStrategyFirstComeFirstServe + }, + { wallet: vaultOwner, autofill: true } +) + +const vaultNode = vaultCreateResult.result.meta.AffectedNodes.find( + (node) => node.CreatedNode?.LedgerEntryType === 'Vault' +) +const vaultID = vaultNode.CreatedNode.LedgerIndex +const vaultShareMPTIssuanceId = vaultNode.CreatedNode.NewFields.ShareMPTID + +// Step 6: Make an initial deposit so withdraw example has shares to work with +process.stdout.write('Setting up tutorial: 6/7\r') + +const initialDepositResult = await client.submitAndWait( + { + TransactionType: 'VaultDeposit', + Account: depositor.address, + VaultID: vaultID, + Amount: { + mpt_issuance_id: mptIssuanceId, + value: '1000' + } + }, + { wallet: depositor, autofill: true } +) + +if (initialDepositResult.result.meta.TransactionResult !== 'tesSUCCESS') { + console.error('\nInitial deposit failed:', initialDepositResult.result.meta.TransactionResult) + await client.disconnect() + process.exit(1) +} + +// Step 7: Save setup data to file +process.stdout.write('Setting up tutorial: 7/7\r') + +const setupData = { + mptIssuer: { + address: mptIssuer.address, + seed: mptIssuer.seed + }, + mptIssuanceId, + domainOwner: { + address: domainOwner.address, + seed: domainOwner.seed + }, + domainId, + credentialType: credType, + depositor: { + address: depositor.address, + seed: depositor.seed + }, + vaultOwner: { + address: vaultOwner.address, + seed: vaultOwner.seed + }, + vaultID, + vaultShareMPTIssuanceId +} + +fs.writeFileSync('vaultSetup.json', JSON.stringify(setupData, null, 2)) + +process.stdout.write('Setting up tutorial: Complete!\n') + +await client.disconnect() diff --git a/_code-samples/vaults/js/withdraw.js b/_code-samples/vaults/js/withdraw.js index 0ab4ff00..71618f4c 100644 --- a/_code-samples/vaults/js/withdraw.js +++ b/_code-samples/vaults/js/withdraw.js @@ -1,20 +1,29 @@ import xrpl from "xrpl" +import { execSync } from "child_process" +import fs from "fs" -// Connect to the network ---------------------- -// This is a lending protocol-specific devnet. This network may be taken -// offline once the lending protocol is live on mainnet. -const client = new xrpl.Client("wss://lend.devnet.rippletest.net:51233") +// Auto-run setup if needed +if (!fs.existsSync("vaultSetup.json")) { + console.log(`\n=== Vault setup data doesn't exist. Running setup script... ===\n`) + execSync("node vaultSetup.js", { stdio: "inherit" }) +} + +// Load setup data +const setupData = JSON.parse(fs.readFileSync("vaultSetup.json", "utf8")) + +// Connect to the network +const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233") await client.connect() // Get depositor account -const depositor = xrpl.Wallet.fromSeed("sEdVSq9Zsv8vQwfivTk37bWxrvpnruf") +const depositor = xrpl.Wallet.fromSeed(setupData.depositor.seed) // The ID of the vault to withraw from -const vaultID = "6AC4EC2D775C6275D314996D6ECDD16DCB9382A29FDB769951C42192FCED76EF" +const vaultID = setupData.vaultID // The ID of the vault's asset (MPT Issuance) -const assetMPTIssuanceId = "0003E3B486D3DACD8BB468AB33793B9626BD894A92AB3AB4" +const assetMPTIssuanceId = setupData.mptIssuanceId // The ID of the vault's share (MPT Issuance) -const shareMPTIssuanceId = "0000000152E7CD364F869E832EDB806C4A7AD8B3D0C151C5" +const shareMPTIssuanceId = setupData.vaultShareMPTIssuanceId console.log(`Depositor address: ${depositor.address}`) console.log(`Vault ID: ${vaultID}`) diff --git a/docs/xls-65d-single-asset-vault/tutorials/create-a-single-asset-vault.md b/docs/xls-65d-single-asset-vault/tutorials/create-a-single-asset-vault.md index 318a0d8b..d44a841a 100644 --- a/docs/xls-65d-single-asset-vault/tutorials/create-a-single-asset-vault.md +++ b/docs/xls-65d-single-asset-vault/tutorials/create-a-single-asset-vault.md @@ -57,7 +57,10 @@ npm install xrpl ### 2. Set up client and accounts -To get started, import the client library and instantiate a client to connect to the XRPL. +To get started, import the necessary libraries and instantiate a client to connect to the XRPL. This example imports: + +- `xrpl`: Used for XRPL client connection and transaction handling. +- `fs` and `child_process`: Used to run tutorial setup scripts. {% tabs %} {% tab label="JavaScript" %} @@ -73,7 +76,7 @@ Next, fund a vault owner account, define the MPT issuance ID for the vault's ass {% /tab %} {% /tabs %} -The example uses an existing MPT issuance and permissioned domain, but you can also provide your own values. If you want to create a public vault, you don't need to provide the `domainId`. +The example uses an existing MPT issuance and permissioned domain data from the `vaultSetup.js` script, but you can also provide your own values. If you want to create a public vault, you don't need to provide the `domainId`. ### 3. Prepare VaultCreate transaction diff --git a/docs/xls-65d-single-asset-vault/tutorials/deposit-into-a-vault.md b/docs/xls-65d-single-asset-vault/tutorials/deposit-into-a-vault.md index 9c999830..37078da9 100644 --- a/docs/xls-65d-single-asset-vault/tutorials/deposit-into-a-vault.md +++ b/docs/xls-65d-single-asset-vault/tutorials/deposit-into-a-vault.md @@ -56,11 +56,14 @@ npm install xrpl ### 2. Set up client and accounts -To get started, import the client library and instantiate a client to connect to the XRPL. +To get started, import the necessary libraries and instantiate a client to connect to the XRPL. This example imports: + +- `xrpl`: Used for XRPL client connection and transaction handling. +- `fs` and `child_process`: Used to run tutorial setup scripts. {% tabs %} {% tab label="JavaScript" %} -{% code-snippet file="/_code-samples/vaults/js/deposit.js" language="js" from="import xrpl" before="const depositor" /%} +{% code-snippet file="/_code-samples/vaults/js/deposit.js" language="js" from="import xrpl" before="// You can replace" /%} {% /tab %} {% /tabs %} @@ -68,14 +71,14 @@ Provide the depositing account and specify the vault details. The depositor must {% tabs %} {% tab label="JavaScript" %} -{% code-snippet file="/_code-samples/vaults/js/deposit.js" language="js" from="depositor =" before="// Get initial vault" /%} +{% code-snippet file="/_code-samples/vaults/js/deposit.js" language="js" from="// You can replace" before="// Get initial vault" /%} {% /tab %} {% /tabs %} {% admonition type="info" name="Note" %} -This tutorial deposits to an existing private vault. A preconfigured depositor account is used, which has: +This example uses an existing vault and depositor account from the `vaultSetup.js` script, but you can replace these values with your own. The preconfigured depositor account has: - Valid [Credentials](https://xrpl.org/docs/concepts/decentralized-storage/credentials) in the vault's [Permissioned Domain](https://xrpl.org/docs/concepts/tokens/decentralized-exchange/permissioned-domains). -- A positive balance of the MPT in the vault. +- A positive balance of the MPT in the vault. If you wish to deposit in a different vault, you can replace the relevant values with your own. {% /admonition %} diff --git a/docs/xls-65d-single-asset-vault/tutorials/withdraw-from-a-vault.md b/docs/xls-65d-single-asset-vault/tutorials/withdraw-from-a-vault.md index 3a9ef9d0..3527fa30 100644 --- a/docs/xls-65d-single-asset-vault/tutorials/withdraw-from-a-vault.md +++ b/docs/xls-65d-single-asset-vault/tutorials/withdraw-from-a-vault.md @@ -51,7 +51,9 @@ npm install xrpl ### 2. Set up client and accounts -To get started, import the client library and instantiate a client to connect to the XRPL. +To get started, import the necessary libraries and instantiate a client to connect to the XRPL. This example imports: +- `xrpl`: Used for XRPL client connection and transaction handling. +- `fs` and `child_process`: Used to run tutorial setup scripts. {% tabs %} {% tab label="JavaScript" %} @@ -59,14 +61,14 @@ To get started, import the client library and instantiate a client to connect to {% /tab %} {% /tabs %} -Provide the `depositor` account and specify the vault details: - {% tabs %} {% tab label="JavaScript" %} {% code-snippet file="/_code-samples/vaults/js/withdraw.js" language="js" from="// Get depositor account" before="// Get initial vault" /%} {% /tab %} {% /tabs %} +This example uses preconfigured accounts and vault data from the `vaultSetup.js` script, but you can replace `depositor`, `vaultID`, `assetMPTIssuanceId`, and `shareMPTIssuanceId` with your own values. + ### 3. Check initial vault state Before withdrawing, check the vault's current state to see its total assets and available liquidity.