Skip to content

Commit c2fc8c5

Browse files
committed
bug: rectify the issue where VaultTransactions and VaultLoans were not displayed
1 parent 556e2ba commit c2fc8c5

File tree

5 files changed

+357
-18
lines changed

5 files changed

+357
-18
lines changed

create-vault.js

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
const xrpl = require('xrpl')
2+
const { deriveKeypair, sign } = require('ripple-keypairs')
3+
const { encodeForSigning } = require('ripple-binary-codec')
4+
5+
async function createVaultAndBrokers() {
6+
// Connect to devnet
7+
// const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233/');
8+
const client = new xrpl.Client('wss://lend.devnet.rippletest.net:51233/')
9+
await client.connect()
10+
11+
console.log('Connected to XRPL devnet\n')
12+
13+
// Create and fund wallets via faucet
14+
// const faucetHost = 'faucet.devnet.rippletest.net';
15+
const faucetHost = 'lend-faucet.devnet.rippletest.net'
16+
const faucetPath = '/accounts'
17+
18+
console.log('Funding wallets via faucet...')
19+
const [
20+
{ wallet: vaultOwnerWallet },
21+
{ wallet: borrowerWallet },
22+
{ wallet: depositorWallet },
23+
] = await Promise.all([
24+
client.fundWallet(null, { faucetHost, faucetPath }),
25+
client.fundWallet(null, { faucetHost, faucetPath }),
26+
client.fundWallet(null, { faucetHost, faucetPath }),
27+
])
28+
console.log('Wallets funded successfully!\n')
29+
30+
console.log('Vault Owner address:', vaultOwnerWallet.address)
31+
console.log('Borrower address:', borrowerWallet.address)
32+
console.log('Depositor address:', depositorWallet.address)
33+
let createImpairedLoan
34+
let createDefaultedLoan
35+
36+
// ========================================
37+
// Step 1: Create Vault
38+
// ========================================
39+
console.log('\n📦 Creating Vault...')
40+
const vaultCreateTx = {
41+
TransactionType: 'VaultCreate',
42+
Account: vaultOwnerWallet.address,
43+
Asset: { currency: 'XRP' },
44+
}
45+
46+
const vaultResult = await client.submitAndWait(vaultCreateTx, {
47+
wallet: vaultOwnerWallet,
48+
})
49+
50+
if (vaultResult.result.meta.TransactionResult !== 'tesSUCCESS') {
51+
throw new Error(
52+
`Vault creation failed: ${vaultResult.result.meta.TransactionResult}`,
53+
)
54+
}
55+
56+
// Extract Vault ID from metadata
57+
const vaultCreatedNode = vaultResult.result.meta.AffectedNodes.find(
58+
(node) => node.CreatedNode && node.CreatedNode.LedgerEntryType === 'Vault',
59+
)
60+
const vaultId = vaultCreatedNode.CreatedNode.LedgerIndex
61+
62+
console.log('✅ Vault created successfully!')
63+
console.log('Vault ID:', vaultId)
64+
console.log(`View at: http://localhost:3000/vault/${vaultId}`)
65+
66+
// ========================================
67+
// Step 2: Deposit XRP into Vault
68+
// ========================================
69+
console.log('\n💵 Depositing funds into Vault...')
70+
71+
const depositAmount = '10000000' // 10 XRP in drops
72+
const vaultDepositTx = {
73+
TransactionType: 'VaultDeposit',
74+
Account: depositorWallet.address,
75+
VaultID: vaultId,
76+
Amount: depositAmount,
77+
}
78+
79+
const depositResult = await client.submitAndWait(vaultDepositTx, {
80+
wallet: depositorWallet,
81+
})
82+
83+
if (depositResult.result.meta.TransactionResult !== 'tesSUCCESS') {
84+
throw new Error(
85+
`Vault deposit failed: ${depositResult.result.meta.TransactionResult}`,
86+
)
87+
}
88+
89+
console.log(`✅ Deposited ${xrpl.dropsToXrp(depositAmount)} XRP into vault`)
90+
91+
// ========================================
92+
// Step 3: Create Three Loan Brokers with varying configs
93+
// ========================================
94+
console.log('\n🏦 Creating Loan Brokers...\n')
95+
96+
const brokerConfigs = [
97+
{ name: 'Broker Alpha' },
98+
{ name: 'Broker Beta' },
99+
{ name: 'Broker Gamma' },
100+
]
101+
102+
const brokerIds = []
103+
104+
for (const config of brokerConfigs) {
105+
console.log(`Creating ${config.name}...`)
106+
107+
// Use minimal transaction like lendingSetup.js - extra fields cause signature issues
108+
const loanBrokerSetTx = {
109+
TransactionType: 'LoanBrokerSet',
110+
Account: vaultOwnerWallet.address,
111+
VaultID: vaultId,
112+
}
113+
114+
const brokerResult = await client.submitAndWait(loanBrokerSetTx, {
115+
wallet: vaultOwnerWallet,
116+
autofill: true,
117+
})
118+
119+
if (brokerResult.result.meta.TransactionResult !== 'tesSUCCESS') {
120+
console.error(
121+
`❌ ${config.name} creation failed:`,
122+
brokerResult.result.meta.TransactionResult,
123+
)
124+
continue
125+
}
126+
127+
// Extract Loan Broker ID from metadata
128+
const brokerCreatedNode = brokerResult.result.meta.AffectedNodes.find(
129+
(node) =>
130+
node.CreatedNode && node.CreatedNode.LedgerEntryType === 'LoanBroker',
131+
)
132+
const brokerId = brokerCreatedNode.CreatedNode.LedgerIndex
133+
134+
brokerIds.push({
135+
name: config.name,
136+
id: brokerId,
137+
config,
138+
})
139+
140+
console.log(` ✅ ${config.name} created`)
141+
console.log(` ID: ${brokerId}\n`)
142+
}
143+
144+
// ========================================
145+
// Step 4: Create Three Loans for Each Broker
146+
// ========================================
147+
console.log('\n💰 Creating Loans...\n')
148+
149+
// Suppress console warning from autofilling LoanSet
150+
const originalWarn = console.warn
151+
console.warn = () => {}
152+
153+
const allLoans = []
154+
155+
for (const broker of brokerIds) {
156+
console.log(`Creating loans for ${broker.name}...`)
157+
158+
// Define 3 loans with different configurations
159+
// PrincipalRequested is in drops (1 XRP = 1,000,000 drops)
160+
// InterestRate is in basis points (500 = 5%)
161+
const loanConfigs = [
162+
{
163+
name: 'Loan 1',
164+
PrincipalRequested: '2000000', // 2 XRP
165+
InterestRate: 500, // 5%
166+
PaymentTotal: 1,
167+
PaymentInterval: 2592000, // 30 days
168+
},
169+
{
170+
name: 'Loan 2',
171+
PrincipalRequested: '3000000', // 3 XRP
172+
InterestRate: 500, // 5%
173+
PaymentTotal: 1,
174+
PaymentInterval: 2592000, // 30 days
175+
},
176+
{
177+
name: 'Loan 3',
178+
PrincipalRequested: '1000000', // 1 XRP
179+
InterestRate: 500, // 5%
180+
PaymentTotal: 1,
181+
PaymentInterval: 2592000, // 30 days
182+
},
183+
]
184+
185+
for (const loanConfig of loanConfigs) {
186+
try {
187+
// Prepare LoanSet transaction
188+
const loanSetTx = await client.autofill({
189+
TransactionType: 'LoanSet',
190+
Account: vaultOwnerWallet.address,
191+
Counterparty: borrowerWallet.address,
192+
LoanBrokerID: broker.id,
193+
PrincipalRequested: loanConfig.PrincipalRequested,
194+
InterestRate: loanConfig.InterestRate,
195+
PaymentTotal: loanConfig.PaymentTotal,
196+
PaymentInterval: loanConfig.PaymentInterval,
197+
})
198+
199+
// Loan broker signs first
200+
const loanBrokerSignature = vaultOwnerWallet.sign(loanSetTx)
201+
const decodedLoanBrokerSignature = xrpl.decode(
202+
loanBrokerSignature.tx_blob,
203+
)
204+
205+
// Borrower signs second
206+
const keypair = deriveKeypair(borrowerWallet.seed)
207+
const encodedTx = encodeForSigning(decodedLoanBrokerSignature)
208+
const borrowerSignature = sign(encodedTx, keypair.privateKey)
209+
210+
const counterpartySignature = {
211+
SigningPubKey: keypair.publicKey,
212+
TxnSignature: borrowerSignature,
213+
}
214+
215+
// Form fully signed LoanSet transaction
216+
const signedLoanSetTx = decodedLoanBrokerSignature
217+
signedLoanSetTx.CounterpartySignature = counterpartySignature
218+
219+
// Submit and wait for validation
220+
const loanResult = await client.submitAndWait(signedLoanSetTx)
221+
222+
if (loanResult.result.meta.TransactionResult !== 'tesSUCCESS') {
223+
console.error(
224+
` ❌ ${loanConfig.name} creation failed:`,
225+
loanResult.result.meta.TransactionResult,
226+
)
227+
continue
228+
}
229+
230+
// Extract Loan ID from metadata
231+
const loanCreatedNode = loanResult.result.meta.AffectedNodes.find(
232+
(node) =>
233+
node.CreatedNode && node.CreatedNode.LedgerEntryType === 'Loan',
234+
)
235+
const loanId = loanCreatedNode.CreatedNode.LedgerIndex
236+
237+
allLoans.push({
238+
brokerName: broker.name,
239+
loanName: loanConfig.name,
240+
loanId,
241+
principal: loanConfig.PrincipalRequested,
242+
interestRate: loanConfig.InterestRate,
243+
})
244+
245+
console.log(` ✅ ${loanConfig.name} created (ID: ${loanId})`)
246+
247+
// if (!createImpairedLoan) {
248+
// await new Promise(r => setTimeout(r, 1000));
249+
250+
// const loanManageTx = await client.autofill({
251+
// TransactionType: 'LoanManage',
252+
// Account: broker.address,
253+
// Flags: 0x00020000,
254+
// LoanID: loanId,
255+
// });
256+
// console.log('Creating an impaired loan: ', loanManageTx)
257+
// await client.submitAndWait(loanManageTx);
258+
// createImpairedLoan = true;
259+
// }
260+
} catch (error) {
261+
console.error(` ❌ Error creating ${loanConfig.name}:`, error.message)
262+
}
263+
}
264+
console.log('')
265+
}
266+
267+
// Restore console.warn
268+
console.warn = originalWarn
269+
270+
// ========================================
271+
// Summary
272+
// ========================================
273+
console.log(`\n${'='.repeat(70)}`)
274+
console.log('🎉 SETUP COMPLETE!')
275+
console.log('='.repeat(70))
276+
console.log('\n📋 Summary:')
277+
console.log(`\nVault ID: ${vaultId}`)
278+
console.log(`Asset: XRP`)
279+
console.log(`Owner: ${vaultOwnerWallet.address}`)
280+
console.log(`Depositor: ${depositorWallet.address}`)
281+
console.log(`Borrower: ${borrowerWallet.address}`)
282+
console.log(`Total Deposited: ${xrpl.dropsToXrp(depositAmount)} XRP`)
283+
console.log(`\nLoan Brokers Created: ${brokerIds.length}`)
284+
brokerIds.forEach((broker, index) => {
285+
console.log(`\n${index + 1}. ${broker.name}`)
286+
console.log(` ID: ${broker.id}`)
287+
const brokerLoans = allLoans.filter((l) => l.brokerName === broker.name)
288+
if (brokerLoans.length > 0) {
289+
console.log(` Loans: ${brokerLoans.length}`)
290+
brokerLoans.forEach((loan) => {
291+
console.log(
292+
` - ${loan.loanName}: ${loan.principal} XRP @ ${(loan.interestRate * 100).toFixed(2)}%`,
293+
)
294+
})
295+
}
296+
})
297+
console.log(`\n💰 Total Loans Created: ${allLoans.length}`)
298+
console.log(`\n🌐 View Vault: http://localhost:3000/vault/${vaultId}`)
299+
console.log(`${'='.repeat(70)}\n`)
300+
301+
await client.disconnect()
302+
}
303+
304+
createVaultAndBrokers().catch(console.error)

src/containers/Vault/VaultHeader/index.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import { useTokenToUSDRate } from '../../shared/hooks/useTokenToUSDRate'
99
import { RouteLink } from '../../shared/routing'
1010
import { MPT_ROUTE } from '../../App/routes'
1111
import SocketContext from '../../shared/SocketContext'
12-
import { getLedgerEntry } from '../../../rippled/lib/rippled'
12+
import { getMPTIssuance } from '../../../rippled/lib/rippled'
1313
import { decodeVaultData, formatAmount, parseVaultWebsite } from '../utils'
1414
import { shortenMPTID } from '../../shared/utils'
1515
import './styles.scss'
16+
import { useAnalytics } from '../../shared/analytics'
1617

1718
interface VaultData {
1819
Owner?: string
@@ -68,6 +69,7 @@ const getAssetCurrency = (asset: VaultData['Asset']): string =>
6869
export const VaultHeader = ({ data, vaultId, displayCurrency }: Props) => {
6970
const { t } = useTranslation()
7071
const language = useLanguage()
72+
const { trackException } = useAnalytics()
7173
const rippledSocket = useContext(SocketContext)
7274
const { rate: tokenToUsdRate } = useTokenToUSDRate(data.Asset)
7375

@@ -105,13 +107,16 @@ export const VaultHeader = ({ data, vaultId, displayCurrency }: Props) => {
105107
['getMPTIssuance', vaultShareMptId],
106108
async () => {
107109
if (!vaultShareMptId) return null
108-
const resp = await getLedgerEntry(rippledSocket, {
109-
index: vaultShareMptId,
110-
})
110+
const resp = await getMPTIssuance(rippledSocket, vaultShareMptId)
111111
return resp?.node
112112
},
113113
{
114114
enabled: !!vaultShareMptId,
115+
onError: (e: any) => {
116+
trackException(
117+
`Error fetching MPT Issuance data for MPT ID ${vaultShareMptId} --- ${JSON.stringify(e)}`,
118+
)
119+
},
115120
},
116121
)
117122

src/containers/Vault/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ export const Vault = () => {
122122
return <Page vaultId={vaultId}>{renderError()}</Page>
123123
}
124124

125-
// Get the account ID for transactions (PseudoAccount or Owner)
126-
const transactionAccountId = vaultData?.PseudoAccount
125+
// Get the Vault's (Pseudo)Account ID for transactions
126+
const transactionAccountId = vaultData?.Account
127127

128128
// Get display-friendly currency string from asset
129129
const getAssetCurrencyDisplay = (): string => {

0 commit comments

Comments
 (0)