Files
xrpl-dev-portal/_code-samples/lending-protocol/js/loanManage.js
2026-01-28 01:02:52 -08:00

145 lines
5.3 KiB
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()
// 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}`)
// 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()}`)
// 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))
// 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!')
// 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
// 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)
})
// 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))
// 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 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()