# Manage a Loan This tutorial shows you how to manage a [Loan](/docs/references/protocol/ledger-data/ledger-entry-types/loan) on the XRP Ledger. Loan management includes marking loans as impaired when payments are missed, defaulting loans after the grace period expires, and deleting repaid or defaulted loans. The tutorial demonstrates how a loan broker can manually impair a loan before a payment due date passes (in cases where you suspect a borrower can't make a payment) and default the loan after the grace period expires. LendingProtocol ## Goals By the end of this tutorial, you will be able to: - Check the status of an existing loan. - Manually impair a loan to speed up the default process. - Wait through the loan's grace period. - Default a loan after the grace period expires. ## Prerequisites To complete this tutorial, you should: - Have a basic understanding of the XRP Ledger. - Have an XRP Ledger client library set up in your development environment. This page provides examples for the following: - **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js). See [Get Started Using JavaScript](/docs/tutorials/javascript/build-apps/get-started) for setup steps. ## Source Code You can find the complete source code for this tutorial's examples in the code samples section of this website's repository. ## Steps ### 1. Install dependencies JavaScript From the code sample folder, use npm to install dependencies: ```bash npm install xrpl ``` ### 2. Set up client and accounts 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 set up scripts. JavaScript // IMPORTANT: This example impairs an existing loan, which has a 60 second grace period. // After the 60 seconds pass, this example defaults the loan. import fs from 'fs' import { execSync } from 'child_process' import xrpl from 'xrpl' // Connect to the network ---------------------- const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233') await client.connect() Next, load the loan broker account and loan ID. JavaScript // This step checks for the necessary setup data to run the lending protocol tutorials. // If missing, lendingSetup.js will generate the data. if (!fs.existsSync('lendingSetup.json')) { console.log(`\n=== Lending tutorial data doesn't exist. Running setup script... ===\n`) execSync('node lendingSetup.js', { stdio: 'inherit' }) } // Load preconfigured accounts and LoanID. const setupData = JSON.parse(fs.readFileSync('lendingSetup.json', 'utf8')) // You can replace these values with your own const loanBroker = xrpl.Wallet.fromSeed(setupData.loanBroker.seed) const loanID = setupData.loanID1 console.log(`\nLoan broker address: ${loanBroker.address}`) console.log(`LoanID: ${loanID}`) This example uses preconfigured accounts and loan data from the `lendingSetup.js` script, but you can replace `loanBroker` and `loanID` with your own values. ### 3. Check loan status Check the current status of the loan using the [ledger_entry method](/docs/references/http-websocket-apis/public-api-methods/ledger-methods/ledger_entry): JavaScript // Check loan status before impairment ---------------------- console.log(`\n=== Loan Status ===\n`) const loanStatus = await client.request({ command: 'ledger_entry', index: loanID, ledger_index: 'validated' }) console.log(`Total Amount Owed: ${loanStatus.result.node.TotalValueOutstanding} TSTUSD.`) // Convert Ripple Epoch timestamp to local date and time let nextPaymentDueDate = loanStatus.result.node.NextPaymentDueDate let paymentDue = new Date((nextPaymentDueDate + 946684800) * 1000) console.log(`Payment Due Date: ${paymentDue.toLocaleString()}`) This shows the total amount owed and the next payment due date. The [Ripple Epoch](/docs/references/protocol/data-types/basic-data-types#specifying-time) timestamp is converted to a JavaScript Date object for readability. ### 4. Prepare LoanManage transaction to impair the loan Create the [LoanManage transaction](/docs/references/protocol/transactions/types/loanmanage) with the `tfLoanImpair` flag: JavaScript // Prepare LoanManage transaction to impair the loan ---------------------- console.log(`\n=== Preparing LoanManage transaction to impair loan ===\n`) const loanManageImpair = { TransactionType: 'LoanManage', Account: loanBroker.address, LoanID: loanID, Flags: xrpl.LoanManageFlags.tfLoanImpair } // Validate the impairment transaction before submitting xrpl.validate(loanManageImpair) console.log(JSON.stringify(loanManageImpair, null, 2)) ### 5. Submit LoanManage impairment transaction Sign and submit the `LoanManage` transaction to impair the loan: JavaScript // Sign, submit, and wait for impairment validation ---------------------- console.log(`\n=== Submitting LoanManage impairment transaction ===\n`) const impairResponse = await client.submitAndWait(loanManageImpair, { wallet: loanBroker, autofill: true }) if (impairResponse.result.meta.TransactionResult !== 'tesSUCCESS') { const resultCode = impairResponse.result.meta.TransactionResult console.error('Error: Unable to impair loan:', resultCode) await client.disconnect() process.exit(1) } console.log('Loan impaired successfully!') Verify that the transaction succeeded by checking for a `tesSUCCESS` result code. ### 6. Get loan impairment information Retrieve the loan's grace period and updated payment due date from the transaction result by checking for the `Loan` entry in the transaction metadata: JavaScript // Extract loan impairment info from transaction results ---------------------- let loanNode = impairResponse.result.meta.AffectedNodes.find(node => node.ModifiedNode?.LedgerEntryType === 'Loan' ) // Check grace period and next payment due date const gracePeriod = loanNode.ModifiedNode.FinalFields.GracePeriod nextPaymentDueDate = loanNode.ModifiedNode.FinalFields.NextPaymentDueDate const defaultTime = nextPaymentDueDate + gracePeriod paymentDue = new Date((nextPaymentDueDate + 946684800) * 1000) console.log(`New Payment Due Date: ${paymentDue.toLocaleString()}`) console.log(`Grace Period: ${gracePeriod} seconds`) // Convert current time to Ripple Epoch timestamp const currentTime = Math.floor(Date.now() / 1000) - 946684800 let secondsUntilDefault = defaultTime - currentTime The loan can only be defaulted after the grace period expires. The example calculates when the grace period ends and displays a countdown. ### 7. Wait for grace period to expire This countdown displays the remaining seconds in real-time. Once the grace period expires, the loan can be defaulted. JavaScript // Countdown until loan can be defaulted ---------------------- console.log(`\n=== Countdown until loan can be defaulted ===\n`) await new Promise((resolve) => { const countdown = setInterval(() => { if (secondsUntilDefault <= 0) { clearInterval(countdown) process.stdout.write('\rGrace period expired. Loan can now be defaulted.\n') resolve() } else { process.stdout.write(`\r${secondsUntilDefault} seconds...`) secondsUntilDefault-- } }, 1000) }) ### 8. Prepare LoanManage transaction to default the loan After the grace period expires, create a `LoanManage` transaction with the `tfLoanDefault` flag: JavaScript // Prepare LoanManage transaction to default the loan ---------------------- console.log(`\n=== Preparing LoanManage transaction to default loan ===\n`) const loanManageDefault = { TransactionType: 'LoanManage', Account: loanBroker.address, LoanID: loanID, Flags: xrpl.LoanManageFlags.tfLoanDefault } // Validate the default transaction before submitting xrpl.validate(loanManageDefault) console.log(JSON.stringify(loanManageDefault, null, 2)) ### 9. Submit LoanManage default transaction Sign and submit the `LoanManage` transaction to default the loan: JavaScript // Sign, submit, and wait for default validation ---------------------- console.log(`\n=== Submitting LoanManage default transaction ===\n`) const defaultResponse = await client.submitAndWait(loanManageDefault, { wallet: loanBroker, autofill: true }) if (defaultResponse.result.meta.TransactionResult !== 'tesSUCCESS') { const resultCode = defaultResponse.result.meta.TransactionResult console.error('Error: Unable to default loan:', resultCode) await client.disconnect() process.exit(1) } console.log('Loan defaulted successfully!') Verify that the transaction succeeded by checking for a `tesSUCCESS` result code. ### 10. Verify loan default status Confirm the loan has been defaulted by checking the loan flags: JavaScript // Verify loan default status from transaction results ---------------------- console.log(`\n=== Checking final loan status ===\n`) loanNode = defaultResponse.result.meta.AffectedNodes.find(node => node.ModifiedNode?.LedgerEntryType === 'Loan' ) const loanFlags = loanNode.ModifiedNode.FinalFields.Flags console.log(`Final loan flags (parsed): ${JSON.stringify(xrpl.parseTransactionFlags({ TransactionType: 'LoanManage', Flags: loanFlags }))}`) await client.disconnect() The `parseTransactionFlags` function converts the numeric flags to a readable format, showing that the `tfLoanDefault` flag is now set. ## See Also **Concepts**: - [Lending Protocol](/docs/concepts/tokens/lending-protocol) **Tutorials**: - [Create a Loan](/docs/tutorials/how-tos/set-up-lending/use-the-lending-protocol/create-a-loan) **References**: - [LoanManage transaction](/docs/references/protocol/transactions/types/loanmanage) - [Loan entry](/docs/references/protocol/ledger-data/ledger-entry-types/loan)