Feature update and code optimizations
-- added option for lender to liquidate or pre-liquidate loan if conditions are met -- Reduced repeated processing of requests -- added request caching
This commit is contained in:
parent
5d40939171
commit
c6affb6913
@ -50,10 +50,6 @@ strong {
|
|||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
color: rgba(var(--text-color), 0.9);
|
color: rgba(var(--text-color), 0.9);
|
||||||
}
|
}
|
||||||
p:not(:last-of-type),
|
|
||||||
strong:not(:last-of-type) {
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|||||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -48,10 +48,6 @@ strong {
|
|||||||
max-width: 65ch;
|
max-width: 65ch;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
color: rgba(var(--text-color), 0.9);
|
color: rgba(var(--text-color), 0.9);
|
||||||
|
|
||||||
&:not(:last-of-type) {
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|||||||
490
index.html
490
index.html
@ -643,7 +643,7 @@
|
|||||||
`: html``}
|
`: html``}
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
loanProcess(details = {}) {
|
loanProcess(processId) {
|
||||||
const {
|
const {
|
||||||
type,
|
type,
|
||||||
loanOpeningProcessID,
|
loanOpeningProcessID,
|
||||||
@ -653,7 +653,7 @@
|
|||||||
collateralRequestID, loanResponseID, collateralLockRequestID, collateralLockAckID, loanID, closingTxID,
|
collateralRequestID, loanResponseID, collateralLockRequestID, collateralLockAckID, loanID, closingTxID,
|
||||||
unlockCollateralRequestTime, hasRequestedCollateralUnlock, unlockCollateralAckTime, hasRefundedCollateral,
|
unlockCollateralRequestTime, hasRequestedCollateralUnlock, unlockCollateralAckTime, hasRefundedCollateral,
|
||||||
unlockTxHex
|
unlockTxHex
|
||||||
} = details
|
} = uiGlobals.inProcessRequests[processId]
|
||||||
if (type === 'loanOpening') {
|
if (type === 'loanOpening') {
|
||||||
return Component(() => {
|
return Component(() => {
|
||||||
const [verifyingCollateral, setVerifyCollateral] = useState(false)
|
const [verifyingCollateral, setVerifyCollateral] = useState(false)
|
||||||
@ -1086,6 +1086,8 @@
|
|||||||
lender, lender_sign, loan_amount, loan_id, loan_opening_process_id, loan_transfer_id,
|
lender, lender_sign, loan_amount, loan_id, loan_opening_process_id, loan_transfer_id,
|
||||||
open_time, close_time, policy_id } = btcMortgage.loans[loanID];
|
open_time, close_time, policy_id } = btcMortgage.loans[loanID];
|
||||||
|
|
||||||
|
const { hasRepaidLoan, hasRefundedCollateral, collateralUnlockAckTime, hasRequestedCollateralLiquidation, hasRequestedCollateralPreLiquidation } = uiGlobals.activeLoanQueries[loanID] || {}
|
||||||
|
|
||||||
const amountDue = btcMortgage.util.calcDueAmount(loan_amount, policy_id, open_time)
|
const amountDue = btcMortgage.util.calcDueAmount(loan_amount, policy_id, open_time)
|
||||||
const [isRepayingLoan, setIsRepayingLoan] = useState(false)
|
const [isRepayingLoan, setIsRepayingLoan] = useState(false)
|
||||||
async function initLoanRepayment() {
|
async function initLoanRepayment() {
|
||||||
@ -1109,10 +1111,9 @@
|
|||||||
const isBorrower = floCrypto.isSameAddr(borrower, floDapps.user.id)
|
const isBorrower = floCrypto.isSameAddr(borrower, floDapps.user.id)
|
||||||
const isCoborrower = floCrypto.isSameAddr(coborrower, floDapps.user.id)
|
const isCoborrower = floCrypto.isSameAddr(coborrower, floDapps.user.id)
|
||||||
const isLender = floCrypto.isSameAddr(lender, floDapps.user.id)
|
const isLender = floCrypto.isSameAddr(lender, floDapps.user.id)
|
||||||
let hasStartedRepayment = false
|
|
||||||
let loanStatus = '';
|
let loanStatus = '';
|
||||||
let loanStatusBadge = '';
|
let loanStatusBadge = '';
|
||||||
if (close_time) {
|
if (close_time || hasRefundedCollateral) {
|
||||||
loanStatus = 'Closed'
|
loanStatus = 'Closed'
|
||||||
loanStatusBadge = html`
|
loanStatusBadge = html`
|
||||||
<div class="status">
|
<div class="status">
|
||||||
@ -1121,12 +1122,7 @@
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
} else {
|
} else {
|
||||||
hasStartedRepayment = Object.values({
|
if (hasRepaidLoan) {
|
||||||
...floGlobals.myInbox,
|
|
||||||
...floGlobals.myOutbox
|
|
||||||
})
|
|
||||||
.find(request => request.message.loan_id === loanID)
|
|
||||||
if (hasStartedRepayment) {
|
|
||||||
loanStatus = 'Repaying'
|
loanStatus = 'Repaying'
|
||||||
loanStatusBadge = html`
|
loanStatusBadge = html`
|
||||||
<div class="status">
|
<div class="status">
|
||||||
@ -1160,6 +1156,22 @@
|
|||||||
setIsClaimingCollateral(false)
|
setIsClaimingCollateral(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const hasGoneBelowThreshold = btcMortgage.util.calcRateRatio(floGlobals.btcRate, btcMortgage.policies[policy_id]?.pre_liquidation_threshold) || false;
|
||||||
|
const [isRequestingCollateralPreLiquidation, setIsRequestingCollateralPreLiquidation] = useState(false)
|
||||||
|
async function requestCollateralPreLiquidation() {
|
||||||
|
const confirmation = await getConfirmation('Request collateral pre-liquidation?', { message: `You are about to request for collateral pre-liquidation. Continue?`, confirmText: 'Request', cancelText: 'Cancel' })
|
||||||
|
if (!confirmation)
|
||||||
|
return;
|
||||||
|
setIsRequestingCollateralPreLiquidation(true)
|
||||||
|
try {
|
||||||
|
await btcMortgage.requestBanker.preLiquidateCollateral(loan_id, await floDapps.user.private)
|
||||||
|
notify('Collateral pre-liquidation request sent successfully', 'success')
|
||||||
|
} catch (err) {
|
||||||
|
notify(err, 'error')
|
||||||
|
} finally {
|
||||||
|
setIsRequestingCollateralPreLiquidation(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
return html`
|
return html`
|
||||||
<li class="loan">
|
<li class="loan">
|
||||||
${loanStatusBadge}
|
${loanStatusBadge}
|
||||||
@ -1167,40 +1179,44 @@
|
|||||||
<p>Loan ID: ${loan_id}</p>
|
<p>Loan ID: ${loan_id}</p>
|
||||||
</sm-copy>
|
</sm-copy>
|
||||||
<div class="flex flex-wrap gap-1-5 align-items-start">
|
<div class="flex flex-wrap gap-1-5 align-items-start">
|
||||||
<div class="grid gap-0-3">
|
<div class="flex flex-wrap gap-1-5 align-items-start">
|
||||||
<p>Loan amount</p>
|
|
||||||
<b>${formatAmount(loan_amount, 'usd')}</b>
|
|
||||||
</div>
|
|
||||||
<div class="grid gap-0-3">
|
|
||||||
<p>Collateral amount</p>
|
|
||||||
<b>${formatAmount(collateral_value)}</b>
|
|
||||||
</div>
|
|
||||||
<div class="grid gap-0-3">
|
|
||||||
<p>Duration</p>
|
|
||||||
<b>${btcMortgage.policies[policy_id]?.duration}</b>
|
|
||||||
</div>
|
|
||||||
<div class="grid gap-0-3">
|
|
||||||
<p>Interest</p>
|
|
||||||
<b>${btcMortgage.policies[policy_id]?.interest * 100}% p.a</b>
|
|
||||||
</div>
|
|
||||||
<div class="grid gap-0-3">
|
|
||||||
<p>Opening date</p>
|
|
||||||
<b>${getFormattedTime(open_time)}</b>
|
|
||||||
</div>
|
|
||||||
${close_time ? html`
|
|
||||||
<div class="grid gap-0-3">
|
<div class="grid gap-0-3">
|
||||||
<p>Closing date</p>
|
<p>Loan amount</p>
|
||||||
<b>${getFormattedTime(close_time)}</b>
|
<b>${formatAmount(loan_amount, 'usd')}</b>
|
||||||
</div>
|
|
||||||
`: html`
|
|
||||||
<div class="grid gap-0-3">
|
|
||||||
<p>Loan deadline</p>
|
|
||||||
<b>${getFormattedTime(open_time + decodeDateStringToMilliseconds(btcMortgage.policies[policy_id]?.duration))}</b>
|
|
||||||
</div>
|
</div>
|
||||||
`}
|
<div class="grid gap-0-3">
|
||||||
|
<p>Collateral amount</p>
|
||||||
|
<b>${formatAmount(collateral_value)}</b>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-0-3">
|
||||||
|
<p>Duration</p>
|
||||||
|
<b>${btcMortgage.policies[policy_id]?.duration}</b>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-0-3">
|
||||||
|
<p>Interest</p>
|
||||||
|
<b>${btcMortgage.policies[policy_id]?.interest * 100}% p.a</b>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-wrap gap-1-5 align-items-start">
|
||||||
|
<div class="grid gap-0-3">
|
||||||
|
<p>Opening date</p>
|
||||||
|
<b>${getFormattedTime(open_time)}</b>
|
||||||
|
</div>
|
||||||
|
${loanStatus === 'Closed' ? html`
|
||||||
|
<div class="grid gap-0-3">
|
||||||
|
<p>Closing date</p>
|
||||||
|
<b>${getFormattedTime(close_time || collateralUnlockAckTime)}</b>
|
||||||
|
</div>
|
||||||
|
`: html`
|
||||||
|
<div class="grid gap-0-3">
|
||||||
|
<p>Loan deadline</p>
|
||||||
|
<b>${getFormattedTime(open_time + decodeDateStringToMilliseconds(btcMortgage.policies[policy_id]?.duration))}</b>
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid gap-0-3">
|
<div class="grid gap-0-3">
|
||||||
<p>Interest ${isLender ? 'earned' : close_time ? 'paid' : 'accrued'}</p>
|
<p>Interest ${isLender ? 'earned' : loanStatus === 'Closed' ? 'paid' : 'accrued'}</p>
|
||||||
<b style=${`color: ${isLender ? 'var(--green)' : 'var(--danger-color)'}`}>${formatAmount(amountDue - loan_amount, 'usd')}</b>
|
<b style=${`color: ${isLender ? 'var(--green)' : 'var(--danger-color)'}`}>${formatAmount(amountDue - loan_amount, 'usd')}</b>
|
||||||
</div>
|
</div>
|
||||||
<details>
|
<details>
|
||||||
@ -1241,20 +1257,27 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
`: ''}
|
`: ''}
|
||||||
${isLender && isLoanOverdue ? html`
|
${loanStatus === 'closed' && isLender && isLoanOverdue ? html`
|
||||||
<div class="flex align-center space-between gap-1-5">
|
<div class="flex align-center space-between gap-1-5">
|
||||||
<div class="grid gap-0-3">
|
${hasRequestedCollateralLiquidation ? html`
|
||||||
<h4>Loan repayment overdue</h4>
|
<div class="grid gap-0-3">
|
||||||
<p>Borrower has not repaid the loan even after the deadline. You can now claim the collateral.</p>
|
<h4>Collateral liquidation requested</h4>
|
||||||
</div>
|
<p>Our banker will resolve your request within 48hrs.</p>
|
||||||
<button class="button button--primary margin-left-auto" disabled=${isClaimingCollateral} onclick=${claimCollateral}>
|
</div>
|
||||||
${isClaimingCollateral ? html`
|
`: html`
|
||||||
Claiming collateral
|
<div class="grid gap-0-3">
|
||||||
<sm-spinner class="margin-left-0-5"></sm-spinner>
|
<h4>Loan repayment overdue</h4>
|
||||||
`: html`
|
<p>Borrower has not repaid the loan even after the deadline. You can now claim the collateral.</p>
|
||||||
Claim collateral
|
</div>
|
||||||
`}
|
<button class="button button--primary margin-left-auto" disabled=${isClaimingCollateral} onclick=${claimCollateral}>
|
||||||
</button>
|
${isClaimingCollateral ? html`
|
||||||
|
Claiming collateral
|
||||||
|
<sm-spinner class="margin-left-0-5"></sm-spinner>
|
||||||
|
`: html`
|
||||||
|
Claim collateral
|
||||||
|
`}
|
||||||
|
</button>
|
||||||
|
`}
|
||||||
</div>
|
</div>
|
||||||
`: ''}
|
`: ''}
|
||||||
</li>
|
</li>
|
||||||
@ -1421,7 +1444,7 @@
|
|||||||
}
|
}
|
||||||
let userAddressTimeInterval;
|
let userAddressTimeInterval;
|
||||||
function renderHome(appState) {
|
function renderHome(appState) {
|
||||||
const { lastPage, page, params: { } = {}, wildcards: [section = 'my-loans'] = [] } = appState || {};
|
const { lastPage, page, params: { } = {}, wildcards = [] } = appState || {};
|
||||||
|
|
||||||
const balanceCard = Component(() => {
|
const balanceCard = Component(() => {
|
||||||
const [btcBalance, setBtcBalance] = useState(floGlobals.memoBalance['BTC'])
|
const [btcBalance, setBtcBalance] = useState(floGlobals.memoBalance['BTC'])
|
||||||
@ -1505,7 +1528,7 @@
|
|||||||
case 'type_liquate_collateral_request':
|
case 'type_liquate_collateral_request':
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'type_preliquate_collateral_request':
|
case 'type_pre_liquidate_collateral_request':
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1536,18 +1559,14 @@
|
|||||||
} else {
|
} else {
|
||||||
// user homepage
|
// user homepage
|
||||||
const inbox = Component(() => {
|
const inbox = Component(() => {
|
||||||
const loanRequestsInProcess = Object.values(floGlobals.inProcessRequests).sort((a, b) => {
|
|
||||||
const aTime = a.initiationTime || a.loanResponseTime || a.loanClosedAckTime || a.unlockCollateralRequestTime;
|
|
||||||
const bTime = b.initiationTime || b.loanResponseTime || b.loanClosedAckTime || b.unlockCollateralRequestTime;
|
|
||||||
return bTime - aTime
|
|
||||||
})
|
|
||||||
const { borrowed, coBorrowed, lent } = groupLoans()
|
const { borrowed, coBorrowed, lent } = groupLoans()
|
||||||
const [view, setView] = useState(section)
|
const defaultView = wildcards.length ? wildcards[0] : uiGlobals.sortedProcesses.length ? 'in-process' : 'my-loans'
|
||||||
|
const [view, setView] = useState(defaultView)
|
||||||
let loanRequests = [];
|
let loanRequests = [];
|
||||||
for (const key in floGlobals.loanRequests) {
|
for (const key in floGlobals.loanRequests) {
|
||||||
const { message: { borrower, coborrower, loan_opening_process_id } } = floGlobals.loanRequests[key]
|
const { message: { borrower, coborrower, loan_opening_process_id } } = floGlobals.loanRequests[key]
|
||||||
if (!loan_opening_process_id) continue // TODO: remove this check after all requests are updated
|
if (!loan_opening_process_id) continue // TODO: remove this check after all requests are updated
|
||||||
if (floGlobals.loansOpeningInProcess.has(loan_opening_process_id)) continue // if loan request is in process, don't show loan request
|
if (floGlobals.hasAgreedToLend.has(loan_opening_process_id)) continue // if user has already agreed to lend, don't show the request
|
||||||
loanRequests.push(key)
|
loanRequests.push(key)
|
||||||
}
|
}
|
||||||
function handleChange(e) {
|
function handleChange(e) {
|
||||||
@ -1566,10 +1585,10 @@
|
|||||||
return html`
|
return html`
|
||||||
<section class="grid gap-1">
|
<section class="grid gap-1">
|
||||||
<sm-chips onchange=${handleChange}>
|
<sm-chips onchange=${handleChange}>
|
||||||
${loanRequestsInProcess.length ? html`
|
${uiGlobals.sortedProcesses.length ? html`
|
||||||
<sm-chip value="in-process" selected=${view === 'in-process'}>
|
<sm-chip value="in-process" selected=${view === 'in-process'}>
|
||||||
In process
|
In process
|
||||||
<span class="badge">${loanRequestsInProcess.length}</span>
|
<span class="badge">${uiGlobals.sortedProcesses.length}</span>
|
||||||
</sm-chip>
|
</sm-chip>
|
||||||
` : ''}
|
` : ''}
|
||||||
<sm-chip value="my-loans" selected=${view === 'my-loans'}>
|
<sm-chip value="my-loans" selected=${view === 'my-loans'}>
|
||||||
@ -1612,9 +1631,9 @@
|
|||||||
</div>
|
</div>
|
||||||
`}
|
`}
|
||||||
`: ''}
|
`: ''}
|
||||||
${view === 'in-process' && loanRequestsInProcess.length ? html`
|
${view === 'in-process' && uiGlobals.sortedProcesses.length ? html`
|
||||||
<ul class="grid gap-1">
|
<ul class="grid gap-1">
|
||||||
${loanRequestsInProcess.map(loan => render.loanProcess(loan))}
|
${uiGlobals.sortedProcesses.map(processId => render.loanProcess(processId))}
|
||||||
</ul>
|
</ul>
|
||||||
`: ''}
|
`: ''}
|
||||||
${view === 'coBorrowed' && coBorrowed.length ? html`
|
${view === 'coBorrowed' && coBorrowed.length ? html`
|
||||||
@ -1732,10 +1751,8 @@
|
|||||||
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(floGlobals.myFloID)
|
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(floGlobals.myFloID)
|
||||||
floGlobals.isAdmin = floGlobals.myFloID === floGlobals.adminID
|
floGlobals.isAdmin = floGlobals.myFloID === floGlobals.adminID
|
||||||
floGlobals.loaded = false
|
floGlobals.loaded = false
|
||||||
floGlobals.myInbox = {}
|
|
||||||
floGlobals.myOutbox = {}
|
|
||||||
floGlobals.loanRequests = {}
|
floGlobals.loanRequests = {}
|
||||||
floGlobals.requestTypes = {}
|
uiGlobals.activeLoanQueries = {}
|
||||||
floGlobals.btcRate = 1
|
floGlobals.btcRate = 1
|
||||||
floGlobals.memoBalance = {
|
floGlobals.memoBalance = {
|
||||||
'FLO': 0,
|
'FLO': 0,
|
||||||
@ -1759,24 +1776,23 @@
|
|||||||
callback: (d, e) => {
|
callback: (d, e) => {
|
||||||
if (e) return
|
if (e) return
|
||||||
for (const key in d) {
|
for (const key in d) {
|
||||||
if (
|
switch (d[key].type) {
|
||||||
d[key].type === 'type_unlock_collateral_request' ||
|
case 'type_unlock_collateral_request':
|
||||||
d[key].type === 'type_unlock_collateral_ack' ||
|
case 'type_unlock_collateral_ack':
|
||||||
d[key].type === 'type_refund_collateral_request' ||
|
case 'type_refund_collateral_request':
|
||||||
d[key].type === 'type_refund_collateral_ack' ||
|
case 'type_refund_collateral_ack':
|
||||||
d[key].type === 'type_liquate_collateral_request' ||
|
case 'type_liquate_collateral_request':
|
||||||
d[key].type === 'type_liquate_collateral_ack' ||
|
case 'type_liquate_collateral_ack':
|
||||||
d[key].type === 'type_preliquate_collateral_request' ||
|
case 'type_pre_liquidate_collateral_request':
|
||||||
d[key].type === 'type_preliquate_collateral_ack'
|
case 'type_preLiquidate_collateral_ack':
|
||||||
) {
|
floGlobals.bankerRequests = {
|
||||||
floGlobals.bankerRequests = {
|
...(floGlobals.bankerRequests || {}),
|
||||||
...floGlobals.bankerRequests || {},
|
[key]: d[key]
|
||||||
[key]: d[key]
|
};
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('LOAN REQUESTS', d)
|
console.log('LOAN REQUESTS', d)
|
||||||
processInProcessRequests()
|
|
||||||
if (floGlobals.loaded) {
|
if (floGlobals.loaded) {
|
||||||
router.routeTo(window.location.hash)
|
router.routeTo(window.location.hash)
|
||||||
}
|
}
|
||||||
@ -1785,14 +1801,10 @@
|
|||||||
} else {
|
} else {
|
||||||
const result = await Promise.allSettled([
|
const result = await Promise.allSettled([
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
btcMortgage.viewMyInbox((d, e) => {
|
btcMortgage.viewMyInbox((requests, e) => {
|
||||||
if (e) return
|
if (e) return
|
||||||
floGlobals.myInbox = {
|
console.log('MY INBOX', requests)
|
||||||
...floGlobals.myInbox,
|
processInProcessRequests(requests, { isInbox: true })
|
||||||
...d
|
|
||||||
}
|
|
||||||
console.log('MY INBOX', d)
|
|
||||||
processInProcessRequests()
|
|
||||||
if (floGlobals.loaded) {
|
if (floGlobals.loaded) {
|
||||||
router.routeTo(window.location.hash)
|
router.routeTo(window.location.hash)
|
||||||
}
|
}
|
||||||
@ -1802,14 +1814,15 @@
|
|||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
btcMortgage.listLoanRequests((d, e) => {
|
btcMortgage.listLoanRequests((requests, e) => {
|
||||||
if (e) return
|
if (e) return
|
||||||
|
console.log('LOAN REQUESTS', requests)
|
||||||
floGlobals.loanRequests = {
|
floGlobals.loanRequests = {
|
||||||
...floGlobals.loanRequests,
|
...floGlobals.loanRequests,
|
||||||
...d
|
...requests
|
||||||
}
|
}
|
||||||
console.log('LOAN REQUESTS', d)
|
// if loan requests are from me, process them
|
||||||
processInProcessRequests()
|
processInProcessRequests(requests, { areLoanRequests: true })
|
||||||
if (floGlobals.loaded) {
|
if (floGlobals.loaded) {
|
||||||
router.routeTo(window.location.hash)
|
router.routeTo(window.location.hash)
|
||||||
}
|
}
|
||||||
@ -1820,11 +1833,10 @@
|
|||||||
}),
|
}),
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
floCloudAPI.requestApplicationData('in_process_loan_request', {
|
floCloudAPI.requestApplicationData('in_process_loan_request', {
|
||||||
callback: (d, e) => {
|
callback: (requests, e) => {
|
||||||
if (e) return
|
if (e) return
|
||||||
parseInProcessRequests(d)
|
parseInProcessRequests(requests)
|
||||||
console.log('IN PROCESS LOAN REQUEST', d)
|
console.log('IN PROCESS LOAN REQUEST', requests)
|
||||||
processInProcessRequests()
|
|
||||||
if (floGlobals.loaded) {
|
if (floGlobals.loaded) {
|
||||||
router.routeTo(window.location.hash)
|
router.routeTo(window.location.hash)
|
||||||
}
|
}
|
||||||
@ -1835,19 +1847,15 @@
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all([...getAllInvolvedAddresses()].map(address => {
|
await Promise.all([...uiGlobals.relatedAddresses].map(address => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
floCloudAPI.requestApplicationData(null, {
|
floCloudAPI.requestApplicationData(null, {
|
||||||
senderID: floDapps.user.id,
|
senderID: floDapps.user.id,
|
||||||
receiverID: address,
|
receiverID: address,
|
||||||
callback: (d, e) => {
|
callback: (requests, e) => {
|
||||||
if (e) return
|
if (e) return
|
||||||
floGlobals.myOutbox = {
|
console.log('MY OUTBOX', requests)
|
||||||
...floGlobals.myOutbox || {},
|
processInProcessRequests(requests)
|
||||||
...d
|
|
||||||
}
|
|
||||||
console.log('MY OUTBOX', d)
|
|
||||||
processInProcessRequests()
|
|
||||||
if (floGlobals.loaded) {
|
if (floGlobals.loaded) {
|
||||||
router.routeTo(window.location.hash)
|
router.routeTo(window.location.hash)
|
||||||
}
|
}
|
||||||
@ -1857,7 +1865,6 @@
|
|||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
console.log(result)
|
console.log(result)
|
||||||
processInProcessRequests()
|
|
||||||
if (['#/landing', '#/sign_in', '#/sign_up'].includes(window.location.hash)) {
|
if (['#/landing', '#/sign_in', '#/sign_up'].includes(window.location.hash)) {
|
||||||
history.replaceState(null, null, '#/home')
|
history.replaceState(null, null, '#/home')
|
||||||
router.routeTo('home')
|
router.routeTo('home')
|
||||||
@ -1880,31 +1887,20 @@
|
|||||||
})
|
})
|
||||||
}).catch(error => console.error(error))
|
}).catch(error => console.error(error))
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @param {Object} requests
|
||||||
|
*/
|
||||||
function parseInProcessRequests(requests) {
|
function parseInProcessRequests(requests) {
|
||||||
if (!floGlobals.loansOpeningInProcess)
|
if (!floGlobals.hasAgreedToLend)
|
||||||
floGlobals.loansOpeningInProcess = new Set()
|
floGlobals.hasAgreedToLend = new Set()
|
||||||
for (const key in requests) {
|
for (const key in requests) {
|
||||||
const { message: { loan_opening_process_id, closing_txid } } = requests[key]
|
const { message: { loan_opening_process_id, closing_txid } } = requests[key]
|
||||||
floGlobals.loansOpeningInProcess.add(loan_opening_process_id)
|
floGlobals.hasAgreedToLend.add(loan_opening_process_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function getAllInvolvedAddresses() { // get all addresses involved in loan process (except my address)
|
/**
|
||||||
const addresses = new Set()
|
* @param {string} inputString
|
||||||
for (const key in floGlobals.myInbox) {
|
*/
|
||||||
const { message: { borrower, coborrower, lender } } = floGlobals.myInbox[key]
|
|
||||||
if (borrower)
|
|
||||||
addresses.add(borrower)
|
|
||||||
if (coborrower)
|
|
||||||
addresses.add(coborrower)
|
|
||||||
if (lender)
|
|
||||||
addresses.add(lender)
|
|
||||||
}
|
|
||||||
if (addresses.has(floGlobals.myFloID))
|
|
||||||
addresses.delete(floGlobals.myFloID)
|
|
||||||
if (addresses.has(floGlobals.myBtcID))
|
|
||||||
addresses.delete(floGlobals.myBtcID)
|
|
||||||
return addresses
|
|
||||||
}
|
|
||||||
function decodeDateStringToMilliseconds(inputString) {
|
function decodeDateStringToMilliseconds(inputString) {
|
||||||
// Define a mapping for units to milliseconds (Y: years, M: months, D: days)
|
// Define a mapping for units to milliseconds (Y: years, M: months, D: days)
|
||||||
const unitToMilliseconds = {
|
const unitToMilliseconds = {
|
||||||
@ -1931,22 +1927,18 @@
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const processedRequests = new Set()
|
const completedLoanProcess = new Set()
|
||||||
floGlobals.inProcessRequests = {}
|
uiGlobals.inProcessRequests = {}
|
||||||
function processInProcessRequests() {
|
uiGlobals.sortedProcesses = []
|
||||||
let myLoanRequests = {}
|
uiGlobals.relatedAddresses = new Set()
|
||||||
for (const key in floGlobals.loanRequests) {
|
/**
|
||||||
const { message: { borrower } } = floGlobals.loanRequests[key]
|
* @param {Object} newRequests
|
||||||
if (floCrypto.isSameAddr(borrower, floGlobals.myFloID)) {
|
* @param {Object} options
|
||||||
myLoanRequests[key] = floGlobals.loanRequests[key]
|
* @param {Boolean} options.isInbox
|
||||||
}
|
*/
|
||||||
}
|
function processInProcessRequests(newRequests = {}, options = {}) {
|
||||||
const allMessages = {
|
const { isInbox = false, areLoanRequests = false } = options
|
||||||
...floGlobals.myInbox,
|
for (const key in newRequests) {
|
||||||
...myLoanRequests,
|
|
||||||
...floGlobals.myOutbox
|
|
||||||
}
|
|
||||||
for (const key in allMessages) {
|
|
||||||
const {
|
const {
|
||||||
message: {
|
message: {
|
||||||
borrower, coborrower, lender,
|
borrower, coborrower, lender,
|
||||||
@ -1954,16 +1946,17 @@
|
|||||||
loan_id, closing_txid, unlock_tx_hex, unlock_collateral_id, type_unlock_collateral_ack
|
loan_id, closing_txid, unlock_tx_hex, unlock_collateral_id, type_unlock_collateral_ack
|
||||||
} = {},
|
} = {},
|
||||||
type, time
|
type, time
|
||||||
} = allMessages[key];
|
} = newRequests[key];
|
||||||
if (processedRequests.has(loan_opening_process_id) || Object.values(btcMortgage.loans).find(loan => loan.loan_opening_process_id === loan_opening_process_id)) {
|
if (borrower && areLoanRequests && !floCrypto.isSameAddr(borrower, floDapps.user.id)) continue // if loan request is not from me, ignore
|
||||||
processedRequests.add(loan_opening_process_id)
|
|
||||||
continue // Request has been processed
|
|
||||||
}
|
|
||||||
if (loan_id && btcMortgage.loans[loan_id] && btcMortgage.loans[loan_id].close_time)
|
if (loan_id && btcMortgage.loans[loan_id] && btcMortgage.loans[loan_id].close_time)
|
||||||
continue // Loan closed
|
continue // Loan closed
|
||||||
if (loan_opening_process_id) {
|
if (loan_opening_process_id) {
|
||||||
if (!floGlobals.inProcessRequests[loan_opening_process_id]) {
|
if (completedLoanProcess.has(loan_opening_process_id) || Object.values(btcMortgage.loans).find(loan => loan.loan_opening_process_id === loan_opening_process_id)) {
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id] = {
|
completedLoanProcess.add(loan_opening_process_id)
|
||||||
|
continue // Request has been processed
|
||||||
|
}
|
||||||
|
if (!uiGlobals.inProcessRequests[loan_opening_process_id]) {
|
||||||
|
uiGlobals.inProcessRequests[loan_opening_process_id] = {
|
||||||
loanOpeningProcessID: loan_opening_process_id,
|
loanOpeningProcessID: loan_opening_process_id,
|
||||||
hasProvidedCollateral: false,
|
hasProvidedCollateral: false,
|
||||||
hasAgreedToLend: false,
|
hasAgreedToLend: false,
|
||||||
@ -1972,113 +1965,154 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (borrower) {
|
if (borrower) {
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].borrower = borrower
|
uiGlobals.inProcessRequests[loan_opening_process_id].borrower = borrower
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].isBorrower = floCrypto.isSameAddr(borrower, floDapps.user.id)
|
uiGlobals.inProcessRequests[loan_opening_process_id].isBorrower = floCrypto.isSameAddr(borrower, floDapps.user.id)
|
||||||
|
if (isInbox)
|
||||||
|
uiGlobals.relatedAddresses.add(borrower)
|
||||||
}
|
}
|
||||||
if (coborrower) {
|
if (coborrower) {
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].coborrower = coborrower
|
uiGlobals.inProcessRequests[loan_opening_process_id].coborrower = coborrower
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].isCoborrower = floCrypto.isSameAddr(coborrower, floDapps.user.id)
|
uiGlobals.inProcessRequests[loan_opening_process_id].isCoborrower = floCrypto.isSameAddr(coborrower, floDapps.user.id)
|
||||||
}
|
if (isInbox)
|
||||||
if (loan_amount) {
|
uiGlobals.relatedAddresses.add(coborrower)
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].loanAmount = loan_amount
|
|
||||||
}
|
|
||||||
if (policy_id) {
|
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].policyID = policy_id
|
|
||||||
}
|
}
|
||||||
if (lender) {
|
if (lender) {
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].lender = lender
|
uiGlobals.inProcessRequests[loan_opening_process_id].lender = lender
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].isLender = floCrypto.isSameAddr(lender, floDapps.user.id)
|
uiGlobals.inProcessRequests[loan_opening_process_id].isLender = floCrypto.isSameAddr(lender, floDapps.user.id)
|
||||||
|
if (isInbox)
|
||||||
|
uiGlobals.relatedAddresses.add(lender)
|
||||||
|
}
|
||||||
|
if (loan_amount) {
|
||||||
|
uiGlobals.inProcessRequests[loan_opening_process_id].loanAmount = loan_amount
|
||||||
|
}
|
||||||
|
if (policy_id) {
|
||||||
|
uiGlobals.inProcessRequests[loan_opening_process_id].policyID = policy_id
|
||||||
}
|
}
|
||||||
if (loan_request_id) {
|
if (loan_request_id) {
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].loanRequestID = loan_request_id
|
uiGlobals.inProcessRequests[loan_opening_process_id].loanRequestID = loan_request_id
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].hasProvidedCollateral = true
|
uiGlobals.inProcessRequests[loan_opening_process_id].hasProvidedCollateral = true
|
||||||
}
|
}
|
||||||
if (collateral_lock_id) {
|
if (collateral_lock_id) {
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].collateralLockID = collateral_lock_id
|
uiGlobals.inProcessRequests[loan_opening_process_id].collateralLockID = collateral_lock_id
|
||||||
}
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'type_loan_collateral_request':
|
case 'type_loan_collateral_request':
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].initiationTime = time
|
uiGlobals.inProcessRequests[loan_opening_process_id].initiationTime = time
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].collateralRequestID = key
|
uiGlobals.inProcessRequests[loan_opening_process_id].collateralRequestID = key
|
||||||
break;
|
break;
|
||||||
case 'type_loan_request':
|
case 'type_loan_request':
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].hasProvidedCollateral = true
|
uiGlobals.inProcessRequests[loan_opening_process_id].hasProvidedCollateral = true
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].loanRequestID = key
|
uiGlobals.inProcessRequests[loan_opening_process_id].loanRequestID = key
|
||||||
break;
|
break;
|
||||||
case 'type_loan_response':
|
case 'type_loan_response':
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].loanResponseTime = time
|
uiGlobals.inProcessRequests[loan_opening_process_id].loanResponseTime = time
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].hasAgreedToLend = true
|
uiGlobals.inProcessRequests[loan_opening_process_id].hasAgreedToLend = true
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].loanResponseID = key
|
uiGlobals.inProcessRequests[loan_opening_process_id].loanResponseID = key
|
||||||
break;
|
break;
|
||||||
case "type_collateral_lock_request":
|
case "type_collateral_lock_request":
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].collateralLockRequestID = key
|
uiGlobals.inProcessRequests[loan_opening_process_id].collateralLockRequestID = key
|
||||||
break;
|
break;
|
||||||
case 'type_collateral_lock_ack':
|
case 'type_collateral_lock_ack':
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].collateralLockAckTime = time
|
uiGlobals.inProcessRequests[loan_opening_process_id].collateralLockAckTime = time
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].hasLockedCollateral = true
|
uiGlobals.inProcessRequests[loan_opening_process_id].hasLockedCollateral = true
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].collateralLockAckID = key
|
uiGlobals.inProcessRequests[loan_opening_process_id].collateralLockAckID = key
|
||||||
break;
|
break;
|
||||||
case 'type_refund_collateral_request':
|
case 'type_refund_collateral_request':
|
||||||
floGlobals.inProcessRequests[loan_opening_process_id].hasRequestedCollateralRefund = true
|
uiGlobals.inProcessRequests[loan_opening_process_id].hasRequestedCollateralRefund = true
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (closing_txid) {
|
} else {
|
||||||
if (!floGlobals.inProcessRequests[closing_txid])
|
if (loan_id) {
|
||||||
floGlobals.inProcessRequests[closing_txid] = {
|
if (!uiGlobals.activeLoanQueries[loan_id])
|
||||||
loanID: loan_id,
|
uiGlobals.activeLoanQueries[loan_id] = {
|
||||||
closingTxID: closing_txid,
|
loanID: loan_id,
|
||||||
hasRequestedCollateralRefund: false,
|
}
|
||||||
hasRefundedCollateral: false,
|
switch (type) {
|
||||||
hasPaidLoan: false,
|
case 'type_loan_closed_ack':
|
||||||
type: 'loanClosing'
|
uiGlobals.activeLoanQueries[loan_id].hasRepaidLoan = true
|
||||||
|
break;
|
||||||
|
case 'type_unlock_collateral_request':
|
||||||
|
uiGlobals.activeLoanQueries[loan_id].hasRequestedCollateralUnlock = true
|
||||||
|
break;
|
||||||
|
case 'type_unlock_collateral_ack':
|
||||||
|
uiGlobals.activeLoanQueries[loan_id].hasRefundedCollateral = true
|
||||||
|
uiGlobals.activeLoanQueries[loan_id].collateralUnlockAckTime = time
|
||||||
|
delete uiGlobals.inProcessRequests[closing_txid]
|
||||||
|
completedLoanProcess.add(closing_txid)
|
||||||
|
break;
|
||||||
|
case 'type_liquate_collateral_request':
|
||||||
|
uiGlobals.activeLoanQueries[loan_id].hasRequestedCollateralLiquidation = true
|
||||||
|
break;
|
||||||
|
case 'type_liquate_collateral_ack':
|
||||||
|
uiGlobals.activeLoanQueries[loan_id].hasLiquidatedCollateral = true
|
||||||
|
break;
|
||||||
|
case 'type_pre_liquidate_collateral_request':
|
||||||
|
uiGlobals.activeLoanQueries[loan_id].hasRequestedCollateralPreLiquidation = true
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
const { borrower, coborrower, lender } = btcMortgage.loans[loan_id]
|
|
||||||
if (borrower) {
|
|
||||||
floGlobals.inProcessRequests[closing_txid].borrower = borrower
|
|
||||||
floGlobals.inProcessRequests[closing_txid].isBorrower = floCrypto.isSameAddr(borrower, floDapps.user.id)
|
|
||||||
}
|
}
|
||||||
if (coborrower) {
|
if (closing_txid && !completedLoanProcess.has(closing_txid)) {
|
||||||
floGlobals.inProcessRequests[closing_txid].coborrower = coborrower
|
if (!uiGlobals.inProcessRequests[closing_txid])
|
||||||
floGlobals.inProcessRequests[closing_txid].isCoborrower = floCrypto.isSameAddr(coborrower, floDapps.user.id)
|
uiGlobals.inProcessRequests[closing_txid] = {
|
||||||
}
|
loanID: loan_id,
|
||||||
if (lender) {
|
closingTxID: closing_txid,
|
||||||
floGlobals.inProcessRequests[closing_txid].lender = lender
|
hasRequestedCollateralRefund: false,
|
||||||
floGlobals.inProcessRequests[closing_txid].isLender = floCrypto.isSameAddr(lender, floDapps.user.id)
|
hasRefundedCollateral: false,
|
||||||
}
|
hasPaidLoan: false,
|
||||||
if (unlock_tx_hex) {
|
type: 'loanClosing'
|
||||||
floGlobals.inProcessRequests[closing_txid].unlockTxHex = unlock_tx_hex
|
}
|
||||||
}
|
const { borrower, coborrower, lender } = btcMortgage.loans[loan_id]
|
||||||
switch (type) {
|
if (borrower) {
|
||||||
case 'type_loan_closed_ack':
|
uiGlobals.inProcessRequests[closing_txid].borrower = borrower
|
||||||
floGlobals.inProcessRequests[closing_txid].loanClosedAckTime = time
|
uiGlobals.inProcessRequests[closing_txid].isBorrower = floCrypto.isSameAddr(borrower, floDapps.user.id)
|
||||||
floGlobals.inProcessRequests[closing_txid].hasPaidLoan = true
|
if (isInbox)
|
||||||
break;
|
uiGlobals.relatedAddresses.add(borrower)
|
||||||
case 'type_unlock_collateral_request':
|
}
|
||||||
floGlobals.inProcessRequests[closing_txid].unlockCollateralRequestTime = time
|
if (coborrower) {
|
||||||
floGlobals.inProcessRequests[closing_txid].hasRequestedCollateralUnlock = true
|
uiGlobals.inProcessRequests[closing_txid].coborrower = coborrower
|
||||||
break;
|
uiGlobals.inProcessRequests[closing_txid].isCoborrower = floCrypto.isSameAddr(coborrower, floDapps.user.id)
|
||||||
case 'type_unlock_collateral_ack':
|
if (isInbox)
|
||||||
floGlobals.inProcessRequests[closing_txid].unlockCollateralAckTime = time
|
uiGlobals.relatedAddresses.add(coborrower)
|
||||||
floGlobals.inProcessRequests[closing_txid].hasRefundedCollateral = true
|
}
|
||||||
break;
|
if (lender) {
|
||||||
|
uiGlobals.inProcessRequests[closing_txid].lender = lender
|
||||||
|
uiGlobals.inProcessRequests[closing_txid].isLender = floCrypto.isSameAddr(lender, floDapps.user.id)
|
||||||
|
if (isInbox)
|
||||||
|
uiGlobals.relatedAddresses.add(lender)
|
||||||
|
}
|
||||||
|
if (unlock_tx_hex) {
|
||||||
|
uiGlobals.inProcessRequests[closing_txid].unlockTxHex = unlock_tx_hex
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case 'type_loan_closed_ack':
|
||||||
|
uiGlobals.inProcessRequests[closing_txid].loanClosedAckTime = time
|
||||||
|
uiGlobals.inProcessRequests[closing_txid].hasPaidLoan = true
|
||||||
|
break;
|
||||||
|
case 'type_unlock_collateral_request':
|
||||||
|
uiGlobals.inProcessRequests[closing_txid].unlockCollateralRequestTime = time
|
||||||
|
uiGlobals.inProcessRequests[closing_txid].hasRequestedCollateralUnlock = true
|
||||||
|
break;
|
||||||
|
case 'type_unlock_collateral_ack':
|
||||||
|
uiGlobals.inProcessRequests[closing_txid].unlockCollateralAckTime = time
|
||||||
|
uiGlobals.inProcessRequests[closing_txid].hasRefundedCollateral = true
|
||||||
|
completedLoanProcess.add(closing_txid)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// .reduce((acc, loan) => { // group by borrower, coborrower and lender
|
if (uiGlobals.relatedAddresses.has(floGlobals.myBtcID))
|
||||||
// if (loan.isBorrower)
|
uiGlobals.relatedAddresses.delete(floGlobals.myBtcID)
|
||||||
// acc.borrowing.push(loan)
|
if (uiGlobals.relatedAddresses.has(floGlobals.myFloID))
|
||||||
// else if (loan.isCoborrower)
|
uiGlobals.relatedAddresses.delete(floGlobals.myFloID)
|
||||||
// acc.coBorrowing.push(loan)
|
uiGlobals.sortedProcesses = Object.keys(uiGlobals.inProcessRequests).sort((a, b) => {
|
||||||
// else if (loan.isLender)
|
const aTime = uiGlobals.inProcessRequests[a].initiationTime || uiGlobals.inProcessRequests[a].loanResponseTime || uiGlobals.inProcessRequests[a].loanClosedAckTime || uiGlobals.inProcessRequests[a].unlockCollateralRequestTime;
|
||||||
// acc.lending.push(loan)
|
const bTime = uiGlobals.inProcessRequests[b].initiationTime || uiGlobals.inProcessRequests[b].loanResponseTime || uiGlobals.inProcessRequests[b].loanClosedAckTime || uiGlobals.inProcessRequests[b].unlockCollateralRequestTime;
|
||||||
// return acc
|
return bTime - aTime
|
||||||
// }, {
|
})
|
||||||
// borrowing: [],
|
|
||||||
// coBorrowing: [],
|
|
||||||
// lending: []
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function groupLoans() {
|
function groupLoans() {
|
||||||
return Object.values(btcMortgage.loans)
|
return Object.values(btcMortgage.loans)
|
||||||
.sort((a, b) => b.open_time - a.open_time)
|
.sort((a, b) => b.open_time - a.open_time)
|
||||||
|
|||||||
@ -30,8 +30,7 @@
|
|||||||
TYPE_REFUND_COLLATERAL_ACK = "type_refund_collateral_ack",
|
TYPE_REFUND_COLLATERAL_ACK = "type_refund_collateral_ack",
|
||||||
TYPE_LIQUATE_COLLATERAL_REQUEST = "type_liquate_collateral_request",
|
TYPE_LIQUATE_COLLATERAL_REQUEST = "type_liquate_collateral_request",
|
||||||
TYPE_LIQUATE_COLLATERAL_ACK = "type_liquate_collateral_ack",
|
TYPE_LIQUATE_COLLATERAL_ACK = "type_liquate_collateral_ack",
|
||||||
TYPE_PRELIQUATE_COLLATERAL_REQUEST = "type_preliquate_collateral_request",
|
TYPE_PRE_LIQUIDATE_COLLATERAL_REQUEST = "type_pre_liquidate_collateral_request"
|
||||||
TYPE_PRELIQUATE_COLLATERAL_ACK = "type_preliquate_collateral_ack";
|
|
||||||
|
|
||||||
const POLICIES = {}, LOANS = {};
|
const POLICIES = {}, LOANS = {};
|
||||||
const owned_collateral_locks = {};
|
const owned_collateral_locks = {};
|
||||||
@ -124,7 +123,7 @@
|
|||||||
const util = btcMortgage.util = {
|
const util = btcMortgage.util = {
|
||||||
toFixedDecimal,
|
toFixedDecimal,
|
||||||
encodePeriod, decodePeriod,
|
encodePeriod, decodePeriod,
|
||||||
calcAllowedLoan, calcRequiredCollateral, calcDueAmount,
|
calcAllowedLoan, calcRequiredCollateral, calcDueAmount, calcRateRatio,
|
||||||
findLocker, extractPubKeyFromSign
|
findLocker, extractPubKeyFromSign
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1495,7 +1494,7 @@
|
|||||||
resolve(result);
|
resolve(result);
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
compactIDB.writeData("fail_safe", loan_blockchain_data, token_txid); //fail-safe mech if token is transfered but details not added to blockchain. this helps to retry fail-safe
|
compactIDB.writeData("fail_safe", loan_blockchain_data, token_txid); //fail-safe mech if token is transferred but details not added to blockchain. this helps to retry fail-safe
|
||||||
reject({ error, fail_safe: token_txid })
|
reject({ error, fail_safe: token_txid })
|
||||||
})
|
})
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
@ -1516,7 +1515,7 @@
|
|||||||
if (!floCrypto.isSameAddr(loan_details.lender, collateral_liquate_req.senderID))
|
if (!floCrypto.isSameAddr(loan_details.lender, collateral_liquate_req.senderID))
|
||||||
return reject(RequestValidationError(TYPE_LIQUATE_COLLATERAL_REQUEST, "request not sent by lender"));
|
return reject(RequestValidationError(TYPE_LIQUATE_COLLATERAL_REQUEST, "request not sent by lender"));
|
||||||
if (!verify_liquidationSign(liquidation_sign, loan_details.lender, loan_id, loan_details.lender_sign, btc_liquid_rate))
|
if (!verify_liquidationSign(liquidation_sign, loan_details.lender, loan_id, loan_details.lender_sign, btc_liquid_rate))
|
||||||
return reject("Invalid liquiadtion signature");
|
return reject("Invalid liquidation signature");
|
||||||
checkIfLoanClosedFailed(loan, loan_details.borrower, loan_details.lender).then(result => {
|
checkIfLoanClosedFailed(loan, loan_details.borrower, loan_details.lender).then(result => {
|
||||||
if (result) //close/fail loan data found
|
if (result) //close/fail loan data found
|
||||||
return reject(RequestValidationError(TYPE_LIQUATE_COLLATERAL_REQUEST, "Loan already closed"));
|
return reject(RequestValidationError(TYPE_LIQUATE_COLLATERAL_REQUEST, "Loan already closed"));
|
||||||
@ -1527,8 +1526,8 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// L: request T (banker) to preliquidate collateral when collateral value has dropped to risk threshold
|
// L: request T (banker) to pre-liquidate collateral when collateral value has dropped to risk threshold
|
||||||
btcMortgage.requestBanker.preliquateCollateral = function (loan_id, privKey) {
|
btcMortgage.requestBanker.preLiquidateCollateral = function (loan_id, privKey) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let lender_pubKey = floDapps.user.public;
|
let lender_pubKey = floDapps.user.public;
|
||||||
getLoanDetails(loan_id).then(loan_details => {
|
getLoanDetails(loan_id).then(loan_details => {
|
||||||
@ -1552,7 +1551,7 @@
|
|||||||
floCloudAPI.sendApplicationData({
|
floCloudAPI.sendApplicationData({
|
||||||
loan_id, liquidation_sign,
|
loan_id, liquidation_sign,
|
||||||
liquidate_tx_hex: txHex
|
liquidate_tx_hex: txHex
|
||||||
}, TYPE_PRELIQUATE_COLLATERAL_REQUEST)
|
}, TYPE_PRE_LIQUIDATE_COLLATERAL_REQUEST)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
compactIDB.addData("outbox", result, result.vectorClock);
|
compactIDB.addData("outbox", result, result.vectorClock);
|
||||||
resolve(result);
|
resolve(result);
|
||||||
@ -1564,9 +1563,9 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
btcMortgage.banker.preliquateCollateral = function (collateral_preliquate_req_id, privKey) {
|
btcMortgage.banker.preLiquidateCollateral = function (collateral_pre_liquidate_req_id, privKey) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
validate_preliquateCollateral_request(collateral_preliquate_req_id).then(result => {
|
validate_pre_liquidateCollateral_request(collateral_pre_liquidate_req_id).then(result => {
|
||||||
let { loan_details, liquidate_tx_hex, btc_liquid_rate, liquidation_sign } = result;
|
let { loan_details, liquidate_tx_hex, btc_liquid_rate, liquidation_sign } = result;
|
||||||
//calculate due amount
|
//calculate due amount
|
||||||
let due_amount = calcDueAmount(loan_details.loan_amount, loan_details.policy_id, loan_details.open_time)
|
let due_amount = calcDueAmount(loan_details.loan_amount, loan_details.policy_id, loan_details.open_time)
|
||||||
@ -1591,7 +1590,7 @@
|
|||||||
resolve(result);
|
resolve(result);
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
compactIDB.writeData("fail_safe", loan_blockchain_data, token_txid); //fail-safe mech if token is transfered but details not added to blockchain. this helps to retry fail-safe
|
compactIDB.writeData("fail_safe", loan_blockchain_data, token_txid); //fail-safe mech if token is transferred but details not added to blockchain. this helps to retry fail-safe
|
||||||
reject({ error, fail_safe: token_txid })
|
reject({ error, fail_safe: token_txid })
|
||||||
})
|
})
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
@ -1601,30 +1600,30 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function validate_preliquateCollateral_request(collateral_preliquate_req_id) {
|
function validate_pre_liquidateCollateral_request(collateral_pre_liquidate_req_id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
floCloudAPI.requestApplicationData(TYPE_PRELIQUATE_COLLATERAL_REQUEST, { atVectorClock: collateral_preliquate_req_id }).then(collateral_preliquate_req => {
|
floCloudAPI.requestApplicationData(TYPE_PRE_LIQUIDATE_COLLATERAL_REQUEST, { atVectorClock: collateral_pre_liquidate_req_id }).then(collateral_pre_liquidate_req => {
|
||||||
collateral_preliquate_req = collateral_preliquate_req[collateral_preliquate_req_id];
|
collateral_pre_liquidate_req = collateral_pre_liquidate_req[collateral_pre_liquidate_req_id];
|
||||||
if (!collateral_preliquate_req)
|
if (!collateral_pre_liquidate_req)
|
||||||
return reject(RequestValidationError(TYPE_PRELIQUATE_COLLATERAL_REQUEST, "request not found"));
|
return reject(RequestValidationError(TYPE_PRE_LIQUIDATE_COLLATERAL_REQUEST, "request not found"));
|
||||||
let { loan_id, liquidation_sign, btc_liquid_rate, liquidate_tx_hex } = collateral_preliquate_req.message;
|
let { loan_id, liquidation_sign, btc_liquid_rate, liquidate_tx_hex } = collateral_pre_liquidate_req.message;
|
||||||
getLoanDetails(loan_id).then(loan_details => {
|
getLoanDetails(loan_id).then(loan_details => {
|
||||||
if (!floCrypto.isSameAddr(loan_details.lender, collateral_preliquate_req.senderID))
|
if (!floCrypto.isSameAddr(loan_details.lender, collateral_pre_liquidate_req.senderID))
|
||||||
return reject(RequestValidationError(TYPE_PRELIQUATE_COLLATERAL_REQUEST, "request not sent by lender"));
|
return reject(RequestValidationError(TYPE_PRE_LIQUIDATE_COLLATERAL_REQUEST, "request not sent by lender"));
|
||||||
if (!verify_liquidationSign(liquidation_sign, loan_details.lender, loan_id, loan_details.lender_sign, btc_liquid_rate))
|
if (!verify_liquidationSign(liquidation_sign, loan_details.lender, loan_id, loan_details.lender_sign, btc_liquid_rate))
|
||||||
return reject("Invalid liquiadtion signature");
|
return reject("Invalid liquidation signature");
|
||||||
checkIfLoanClosedFailed(loan, loan_details.borrower, loan_details.lender).then(result => {
|
checkIfLoanClosedFailed(loan, loan_details.borrower, loan_details.lender).then(result => {
|
||||||
if (result) //close/fail loan data found
|
if (result) //close/fail loan data found
|
||||||
return reject(RequestValidationError(TYPE_PRELIQUATE_COLLATERAL_REQUEST, "Loan already closed"));
|
return reject(RequestValidationError(TYPE_PRE_LIQUIDATE_COLLATERAL_REQUEST, "Loan already closed"));
|
||||||
let policy = POLICIES[loan_details.policy_id];
|
let policy = POLICIES[loan_details.policy_id];
|
||||||
if (isNaN(policy.pre_liquidation_threshold))
|
if (isNaN(policy.pre_liquidation_threshold))
|
||||||
return reject("This loan policy doesn't allow pre-liquidation");
|
return reject("This loan policy doesn't allow pre-liquidation");
|
||||||
getRate["USD"].then(cur_btc_rate => {
|
getRate["USD"].then(cur_btc_rate => {
|
||||||
if (cur_btc_rate >= loan_details.btc_start_rate)
|
if (cur_btc_rate >= loan_details.btc_start_rate)
|
||||||
return reject(RequestValidationError(TYPE_PRELIQUATE_COLLATERAL_REQUEST, "BTC rate hasn't reduced from the start rate"));
|
return reject(RequestValidationError(TYPE_PRE_LIQUIDATE_COLLATERAL_REQUEST, "BTC rate hasn't reduced from the start rate"));
|
||||||
let current_rate_ratio = calcRateRatio(cur_btc_rate, loan_details.btc_start_rate)
|
let current_rate_ratio = calcRateRatio(cur_btc_rate, loan_details.btc_start_rate)
|
||||||
if (current_rate_ratio > policy.pre_liquidation_threshold)
|
if (current_rate_ratio > policy.pre_liquidation_threshold)
|
||||||
return reject(RequestValidationError(TYPE_PRELIQUATE_COLLATERAL_REQUEST, "BTC rate hasn't dropped beyond threshold"));
|
return reject(RequestValidationError(TYPE_PRE_LIQUIDATE_COLLATERAL_REQUEST, "BTC rate hasn't dropped beyond threshold"));
|
||||||
resolve({ loan_details, liquidate_tx_hex, btc_liquid_rate, liquidation_sign });
|
resolve({ loan_details, liquidate_tx_hex, btc_liquid_rate, liquidation_sign });
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user