Skip to content

Commit

Permalink
CentrifugeJS: Loan refactor (#1521)
Browse files Browse the repository at this point in the history
  • Loading branch information
onnovisser authored Aug 4, 2023
1 parent 7bb540a commit 97666e0
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 126 deletions.
3 changes: 3 additions & 0 deletions centrifuge-app/src/pages/IssuerPool/Assets/CreateLoan.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export type CreateLoanFormValues = {
discountRate: number | ''
maxBorrowQuantity: number | ''
Isin: string
notional: number | ''
}
}

Expand Down Expand Up @@ -220,6 +221,7 @@ function IssuerCreateLoan() {
discountRate: '',
maxBorrowQuantity: '',
Isin: '',
notional: '',
},
},
onSubmit: async (values, { setSubmitting }) => {
Expand All @@ -234,6 +236,7 @@ function IssuerCreateLoan() {
: null,
Isin: values.pricing.Isin || '',
maturityDate: new Date(values.pricing.maturityDate),
interestRate: Rate.fromPercent(values.pricing.interestRate),
}
: {
valuationMethod: values.pricing.valuationMethod,
Expand Down
30 changes: 21 additions & 9 deletions centrifuge-app/src/pages/IssuerPool/Assets/PricingInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ export function PricingInput({ poolId }: { poolId: string }) {
name="pricing.Isin"
validate={validate.Isin}
/>
<Field name="pricing.notional" validate={combine(required(), positiveNumber(), max(Number.MAX_SAFE_INTEGER))}>
{({ field, meta, form }: FieldProps) => (
<CurrencyInput
{...field}
label="Notional*"
placeholder="0.00"
errorMessage={meta.touched ? meta.error : undefined}
currency={pool?.currency.symbol}
onChange={(value) => form.setFieldValue('pricing.notional', value)}
variant="small"
/>
)}
</Field>
</>
)}

Expand Down Expand Up @@ -93,18 +106,17 @@ export function PricingInput({ poolId }: { poolId: string }) {
max={new Date(Date.now() + 5 * 365 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10)}
/>

<FieldWithErrorMessage
as={NumberInput}
label={<Tooltips type="financingFee" variant="secondary" label="Financing fee*" />}
placeholder="0.00"
rightElement="%"
name="pricing.interestRate"
validate={validate.fee}
/>
{(values.pricing.valuationMethod === 'discountedCashFlow' ||
values.pricing.valuationMethod === 'outstandingDebt') && (
<>
<FieldWithErrorMessage
as={NumberInput}
label={<Tooltips type="financingFee" variant="secondary" label="Financing fee*" />}
placeholder="0.00"
rightElement="%"
name="pricing.interestRate"
validate={validate.fee}
/>

<FieldWithErrorMessage
as={NumberInput}
label={<Tooltips type="advanceRate" variant="secondary" label="Advance rate*" />}
Expand Down
21 changes: 10 additions & 11 deletions centrifuge-app/src/pages/Loan/ExternalFinanceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ export function ExternalFinanceForm({ loan }: { loan: LoanType }) {
const debt = loan.outstandingDebt?.toDecimal() || Dec(0)
const poolReserve = pool?.reserve.available.toDecimal() ?? Dec(0)
const maxBorrow = poolReserve.lessThan(availableFinancing) ? poolReserve : availableFinancing

const maturityDatePassed =
loan?.pricing && 'maturityDate' in loan.pricing && new Date() > new Date(loan.pricing.maturityDate)

Expand Down Expand Up @@ -201,16 +200,16 @@ export function ExternalFinanceForm({ loan }: { loan: LoanType }) {
This is calculated through the amount multiplied by the current price of the asset
</Text>
</Stack>
{poolReserve.lessThan(availableFinancing) ||
('valuationMethod' in loan.pricing && !loan.pricing.maxBorrowAmount && (
<Shelf alignItems="flex-start" justifyContent="start" gap="4px">
<IconInfo size="iconMedium" />
<Text variant="body3">
The pool&apos;s available reserve ({formatBalance(poolReserve, pool?.currency.symbol)}) is smaller
than the available financing
</Text>
</Shelf>
))}
{(poolReserve.lessThan(availableFinancing) ||
('valuationMethod' in loan.pricing && !loan.pricing.maxBorrowAmount)) && (
<Shelf alignItems="flex-start" justifyContent="start" gap="4px">
<IconInfo size="iconMedium" />
<Text variant="body3">
The pool&apos;s available reserve ({formatBalance(poolReserve, pool?.currency.symbol)}) is smaller
than the available financing
</Text>
</Shelf>
)}
<Stack px={1}>
<Button type="submit" loading={isFinanceLoading}>
Finance asset
Expand Down
25 changes: 19 additions & 6 deletions centrifuge-app/src/pages/Loan/FinanceForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CurrencyBalance, findBalance, Loan as LoanType } from '@centrifuge/centrifuge-js'
import { ActiveLoan, CurrencyBalance, findBalance, Loan as LoanType } from '@centrifuge/centrifuge-js'
import { useBalances, useCentrifugeTransaction } from '@centrifuge/centrifuge-react'
import { Button, Card, CurrencyInput, IconInfo, InlineFeedback, Shelf, Stack, Text } from '@centrifuge/fabric'
import BN from 'bn.js'
Expand Down Expand Up @@ -64,7 +64,11 @@ function InternalFinanceForm({ loan }: { loan: LoanType }) {
)

function repayAll() {
doRepayAllTransaction([loan.poolId, loan.id], { account, forceProxyType: 'Borrow' })
const l = loan as ActiveLoan
doRepayAllTransaction([loan.poolId, loan.id, l.totalBorrowed.sub(l.repaid.principal)], {
account,
forceProxyType: 'Borrow',
})
}

const financeForm = useFormik<FinanceValues>({
Expand All @@ -84,8 +88,15 @@ function InternalFinanceForm({ loan }: { loan: LoanType }) {
amount: '',
},
onSubmit: (values, actions) => {
const amount = CurrencyBalance.fromFloat(values.amount, pool.currency.decimals)
doRepayTransaction([loan.poolId, loan.id, amount, new BN(0)], { account, forceProxyType: 'Borrow' })
const l = loan as ActiveLoan
const outstandingPrincipal = l.totalBorrowed.sub(l.repaid.principal)
let amount: BN = CurrencyBalance.fromFloat(values.amount, pool.currency.decimals)
let interest = new BN(0)
if (amount.gt(outstandingPrincipal)) {
interest = amount.sub(outstandingPrincipal)
amount = outstandingPrincipal
}
doRepayTransaction([l.poolId, l.id, amount, interest, new BN(0)], { account, forceProxyType: 'Borrow' })
actions.setSubmitting(false)
},
validateOnMount: true,
Expand All @@ -100,12 +111,12 @@ function InternalFinanceForm({ loan }: { loan: LoanType }) {
if (loan.status === 'Closed') {
return null
}

const debt = loan.outstandingDebt?.toDecimal() || Dec(0)
const poolReserve = pool?.reserve.available.toDecimal() ?? Dec(0)
const maxBorrow = poolReserve.lessThan(availableFinancing) ? poolReserve : availableFinancing
const maxRepay = balance.lessThan(loan.outstandingDebt.toDecimal()) ? balance : loan.outstandingDebt.toDecimal()
const canRepayAll = debtWithMargin?.lte(balance)

const maturityDatePassed =
loan?.pricing && 'maturityDate' in loan.pricing && new Date() > new Date(loan.pricing.maturityDate)

Expand Down Expand Up @@ -145,6 +156,7 @@ function InternalFinanceForm({ loan }: { loan: LoanType }) {
return (
<CurrencyInput
{...field}
value={field.value instanceof Decimal ? field.value.toNumber() : field.value}
label="Amount"
errorMessage={meta.touched ? meta.error : undefined}
secondaryLabel={`${formatBalance(roundDown(maxBorrow), pool?.currency.symbol, 2)} available`}
Expand All @@ -156,7 +168,7 @@ function InternalFinanceForm({ loan }: { loan: LoanType }) {
)
}}
</Field>
{poolReserve.lessThan(availableFinancing) || (
{poolReserve.lessThan(availableFinancing) && (
<Shelf alignItems="flex-start" justifyContent="start" gap="4px">
<IconInfo size="iconMedium" />
<Text variant="body3">
Expand Down Expand Up @@ -204,6 +216,7 @@ function InternalFinanceForm({ loan }: { loan: LoanType }) {
return (
<CurrencyInput
{...field}
value={field.value instanceof Decimal ? field.value.toNumber() : field.value}
label="Amount"
errorMessage={meta.touched ? meta.error : undefined}
secondaryLabel={`${formatBalance(roundDown(maxRepay), pool?.currency.symbol, 2)} available`}
Expand Down
Loading

0 comments on commit 97666e0

Please sign in to comment.