Files
xrpl-dev-portal/_code-samples/vaults/js/withdraw.js
2026-02-17 14:17:07 +00:00

162 lines
5.4 KiB
JavaScript

import xrpl from "xrpl"
import { execSync } from "child_process"
import fs from "fs"
// 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()
// 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}`)
console.log(`Asset MPT issuance ID: ${assetMPTIssuanceId}`)
console.log(`Vault share MPT issuance ID: ${shareMPTIssuanceId}`)
const withdrawAmount = "1"
// Get initial vault state ----------------------
console.log("\n=== Getting initial vault state... ===")
const initialVaultInfo = await client.request({
command: "vault_info",
vault_id: vaultID,
ledger_index: "validated"
})
console.log(`Initial vault state:`)
console.log(` Assets Total: ${initialVaultInfo.result.vault.AssetsTotal}`)
console.log(` Assets Available: ${initialVaultInfo.result.vault.AssetsAvailable}`)
// Check depositor's share balance ----------------------
console.log("\n=== Checking depositor's share balance... ===")
try {
const shareBalanceResult = await client.request({
command: "ledger_entry",
mptoken: {
mpt_issuance_id: shareMPTIssuanceId,
account: depositor.address
},
ledger_index: "validated"
})
const shareBalance = shareBalanceResult.result.node?.MPTAmount
console.log(`Shares held: ${shareBalance}`)
} catch (error) {
if (error.data?.error === 'entryNotFound') {
console.error(`Error: The depositor doesn't hold any vault shares with ID: ${shareMPTIssuanceId}.`)
} else {
console.error(`Error checking MPT: ${error}`)
}
await client.disconnect()
process.exit(1)
}
// Prepare VaultWithdraw transaction ----------------------
console.log(`\n=== Preparing VaultWithdraw transaction ===`)
const vaultWithdrawTx = {
TransactionType: "VaultWithdraw",
Account: depositor.address,
VaultID: vaultID,
Amount: {
mpt_issuance_id: assetMPTIssuanceId,
value: withdrawAmount
},
// Optional: Add Destination field to send assets to a different account
// Destination: "rGg4tHPRGJfewwJkd8immCFx9uSo2GgcoY"
}
// Validate the transaction structure before submitting
xrpl.validate(vaultWithdrawTx)
console.log(JSON.stringify(vaultWithdrawTx, null, 2))
// Submit VaultWithdraw transaction ----------------------
console.log("\n=== Submitting VaultWithdraw transaction... ===")
const withdrawResult = await client.submitAndWait(vaultWithdrawTx, {
wallet: depositor,
autofill: true,
})
if (withdrawResult.result.meta.TransactionResult !== "tesSUCCESS") {
const result_code = withdrawResult.result.meta.TransactionResult
console.error("Error: Unable to withdraw from vault:", result_code)
await client.disconnect()
process.exit(1)
}
console.log("Withdrawal successful!")
// Extract vault state from transaction metadata ----------------------
console.log("\n=== Vault state after withdrawal ===")
const affectedNodes = withdrawResult.result.meta.AffectedNodes
const vaultNode = affectedNodes.find(
(node) => {
const modifiedNode = node.ModifiedNode || node.DeletedNode
return (
modifiedNode &&
modifiedNode.LedgerEntryType === "Vault" &&
modifiedNode.LedgerIndex === vaultID
)
}
)
if (vaultNode) {
if (vaultNode.DeletedNode) {
console.log(` Vault empty (all assets withdrawn)`)
} else {
const vaultFields = vaultNode.ModifiedNode.FinalFields
console.log(` Assets Total: ${vaultFields.AssetsTotal}`)
console.log(` Assets Available: ${vaultFields.AssetsAvailable}`)
}
}
// Get the depositor's share balance ----------------------
console.log("\n=== Depositor's share balance ==")
const depositorShareNode = affectedNodes.find((node) => {
const modifiedNode = node.ModifiedNode || node.DeletedNode
return (
modifiedNode &&
modifiedNode.LedgerEntryType === "MPToken" &&
modifiedNode.FinalFields?.Account === depositor.address &&
modifiedNode.FinalFields?.MPTokenIssuanceID === shareMPTIssuanceId
)
})
if (depositorShareNode) {
if (depositorShareNode.DeletedNode) {
console.log(`No more shares held (redeemed all shares)`)
} else {
const shareFields = depositorShareNode.ModifiedNode.FinalFields
console.log(`Shares held: ${shareFields.MPTAmount}`)
}
}
// Get the depositor's asset balance ----------------------
console.log("\n=== Depositor's asset balance ==")
const depositorAssetNode = affectedNodes.find((node) => {
const assetNode = node.ModifiedNode || node.CreatedNode
const fields = assetNode?.FinalFields || assetNode?.NewFields
return (
assetNode &&
assetNode.LedgerEntryType === "MPToken" &&
fields?.Account === depositor.address &&
fields?.MPTokenIssuanceID === assetMPTIssuanceId
)
})
if (depositorAssetNode) {
const assetNode = depositorAssetNode.ModifiedNode || depositorAssetNode.CreatedNode
const assetFields = assetNode.FinalFields || assetNode.NewFields
console.log(`Balance: ${assetFields.MPTAmount}`)
}
await client.disconnect()