Skip to content

Commit

Permalink
Fix withdraw batch (#2535)
Browse files Browse the repository at this point in the history
  • Loading branch information
onnovisser authored Nov 8, 2024
1 parent bf5f6a9 commit 33c2114
Showing 1 changed file with 147 additions and 144 deletions.
291 changes: 147 additions & 144 deletions centrifuge-app/src/pages/Loan/FinanceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,160 +197,164 @@ function InternalFinanceForm({
<>
{!maturityDatePassed && (
<FormikProvider value={financeForm}>
<Box
px={3}
py={2}
backgroundColor={theme.colors.backgroundSecondary}
borderRadius={10}
border={`1px solid ${theme.colors.borderPrimary}`}
>
<Stack as={Form} gap={2} noValidate ref={financeFormRef}>
<SourceSelect loan={loan} value={source} onChange={onChange} action="finance" />
<Field
name="principal"
validate={combine(positiveNumber(), (val) => {
const principalValue = typeof val === 'number' ? Dec(val) : (val as Decimal)
if (maxAvailable !== UNLIMITED && principalValue.gt(maxAvailable)) {
return `Principal exceeds available financing`
}
return ''
})}
>
{({ field, form }: FieldProps) => {
return (
<CurrencyInput
{...field}
value={field.value instanceof Decimal ? field.value.toNumber() : field.value}
label={isCashLoan(loan) ? 'Amount' : 'Principal'}
currency={displayCurrency}
onChange={(value) => form.setFieldValue('principal', value)}
onSetMax={
maxAvailable !== UNLIMITED ? () => form.setFieldValue('principal', maxAvailable) : undefined
}
/>
)
}}
</Field>
{source === 'other' && (
<Field name="category">
{({ field }: FieldProps) => {
<Form noValidate ref={financeFormRef}>
<Box
px={3}
py={2}
backgroundColor={theme.colors.backgroundSecondary}
borderRadius={10}
border={`1px solid ${theme.colors.borderPrimary}`}
>
<Stack gap={2}>
<SourceSelect loan={loan} value={source} onChange={onChange} action="finance" />
<Field
name="principal"
validate={combine(positiveNumber(), (val) => {
const principalValue = typeof val === 'number' ? Dec(val) : (val as Decimal)
if (maxAvailable !== UNLIMITED && principalValue.gt(maxAvailable)) {
return `Principal exceeds available financing`
}
return ''
})}
>
{({ field, form }: FieldProps) => {
return (
<Select
options={[
{ label: 'Interest', value: 'interest' },
{ label: 'Correction', value: 'correction' },
{ label: 'Miscellaneous', value: 'miscellaneous' },
]}
label="Category"
<CurrencyInput
{...field}
value={field.value instanceof Decimal ? field.value.toNumber() : field.value}
label={isCashLoan(loan) ? 'Amount' : 'Principal'}
currency={displayCurrency}
onChange={(value) => form.setFieldValue('principal', value)}
onSetMax={
maxAvailable !== UNLIMITED ? () => form.setFieldValue('principal', maxAvailable) : undefined
}
/>
)
}}
</Field>
)}
{source === 'reserve' && withdraw.render()}

{poolFees.render()}

<ErrorMessage
type="critical"
condition={totalFinance.gt(0) && maxAvailable !== UNLIMITED && totalFinance.gt(maxAvailable)}
>
{isCashLoan(loan) ? 'Deposit amount' : 'Financing amount'} (
{formatBalance(totalFinance, displayCurrency, 2)}) is greater than the available balance (
{formatBalance(maxAvailable, displayCurrency, 2)}).
</ErrorMessage>

<ErrorMessage
type="default"
condition={
source === 'reserve' && totalFinance.gt(maxAvailable) && pool.reserve.total.gt(pool.reserve.available)
}
>
There is an additional{' '}
{formatBalance(
new CurrencyBalance(pool.reserve.total.sub(pool.reserve.available), pool.currency.decimals),
displayCurrency
)}{' '}
available from repayments or deposits. This requires first executing the orders on the{' '}
<AnchorTextLink href={`#/pools/${pool.id}/liquidity`}>Liquidity tab</AnchorTextLink>.
</ErrorMessage>
</Stack>
</Box>

<Stack gap={2} mt={2} border={`1px solid ${theme.colors.borderPrimary}`} px={3} py={2} borderRadius={10}>
<Text variant="heading4">Transaction summary</Text>
<Box padding={2}>
<Stack gap={1} mb={3}>
<Shelf justifyContent="space-between">
<Tooltip
body={
maxAvailable === UNLIMITED
? 'Unlimited because this is a virtual accounting process.'
: `Balance of the ${source === 'reserve' ? 'onchain reserve' : 'source asset'}.`
}
style={{ pointerEvents: 'auto' }}
>
<Text variant="body2" color="textSecondary">
Available balance
</Text>
</Tooltip>
<Text variant="heading4">
{maxAvailable === UNLIMITED ? 'No limit' : formatBalance(maxAvailable, displayCurrency, 2)}
</Text>
</Shelf>
{source === 'other' && (
<Field name="category">
{({ field }: FieldProps) => {
return (
<Select
options={[
{ label: 'Interest', value: 'interest' },
{ label: 'Correction', value: 'correction' },
{ label: 'Miscellaneous', value: 'miscellaneous' },
]}
label="Category"
{...field}
/>
)
}}
</Field>
)}
{source === 'reserve' && withdraw.render()}

{poolFees.render()}

<ErrorMessage
type="critical"
condition={totalFinance.gt(0) && maxAvailable !== UNLIMITED && totalFinance.gt(maxAvailable)}
>
{isCashLoan(loan) ? 'Deposit amount' : 'Financing amount'} (
{formatBalance(totalFinance, displayCurrency, 2)}) is greater than the available balance (
{formatBalance(maxAvailable, displayCurrency, 2)}).
</ErrorMessage>

<ErrorMessage
type="default"
condition={
source === 'reserve' &&
totalFinance.gt(maxAvailable) &&
pool.reserve.total.gt(pool.reserve.available)
}
>
There is an additional{' '}
{formatBalance(
new CurrencyBalance(pool.reserve.total.sub(pool.reserve.available), pool.currency.decimals),
displayCurrency
)}{' '}
available from repayments or deposits. This requires first executing the orders on the{' '}
<AnchorTextLink href={`#/pools/${pool.id}/liquidity`}>Liquidity tab</AnchorTextLink>.
</ErrorMessage>
</Stack>
</Box>

<Stack gap={1}>
<Stack gap={2} mt={2} border={`1px solid ${theme.colors.borderPrimary}`} px={3} py={2} borderRadius={10}>
<Text variant="heading4">Transaction summary</Text>
<Box padding={2}>
<Stack gap={1} mb={3}>
<Shelf justifyContent="space-between">
<Text variant="body2" color="textSecondary">
{isCashLoan(loan) ? 'Deposit amount' : 'Financing amount'}
<Tooltip
body={
maxAvailable === UNLIMITED
? 'Unlimited because this is a virtual accounting process.'
: `Balance of the ${source === 'reserve' ? 'onchain reserve' : 'source asset'}.`
}
style={{ pointerEvents: 'auto' }}
>
<Text variant="body2" color="textSecondary">
Available balance
</Text>
</Tooltip>
<Text variant="heading4">
{maxAvailable === UNLIMITED ? 'No limit' : formatBalance(maxAvailable, displayCurrency, 2)}
</Text>
<Text variant="heading4">{formatBalance(totalFinance, displayCurrency, 2)}</Text>
</Shelf>
</Stack>

{poolFees.renderSummary()}
</Stack>
<Stack gap={1}>
<Shelf justifyContent="space-between">
<Text variant="body2" color="textSecondary">
{isCashLoan(loan) ? 'Deposit amount' : 'Financing amount'}
</Text>
<Text variant="heading4">{formatBalance(totalFinance, displayCurrency, 2)}</Text>
</Shelf>
</Stack>

{source === 'reserve' ? (
<InlineFeedback status="default">
<Text variant="body2" color="statusDefault">
Stablecoins will be transferred to the designated withdrawal addresses on the specified networks. A
delay may occur before the transfer is completed.
</Text>
</InlineFeedback>
) : source === 'other' ? (
<InlineFeedback status="default">
<Text variant="body2" color="statusDefault">
Virtual accounting process. No onchain stablecoin transfers are expected. This action will lead to
an increase in the NAV of the pool.
</Text>
</InlineFeedback>
) : (
<InlineFeedback status="default">
<Text variant="body2" color="statusDefault">
Virtual accounting process. No onchain stablecoin transfers are expected.
</Text>
</InlineFeedback>
)}
</Box>
</Stack>
{poolFees.renderSummary()}
</Stack>

<Stack>
<Button
type="submit"
loading={isFinanceLoading}
disabled={
!financeForm.values.principal ||
!withdraw.isValid(financeForm) ||
!poolFees.isValid(financeForm) ||
!financeForm.isValid ||
maxAvailable.eq(0)
}
>
{isCashLoan(loan) ? 'Deposit' : 'Finance'}
</Button>
</Stack>
{source === 'reserve' ? (
<InlineFeedback status="default">
<Text variant="body2" color="statusDefault">
Stablecoins will be transferred to the designated withdrawal addresses on the specified networks.
A delay may occur before the transfer is completed.
</Text>
</InlineFeedback>
) : source === 'other' ? (
<InlineFeedback status="default">
<Text variant="body2" color="statusDefault">
Virtual accounting process. No onchain stablecoin transfers are expected. This action will lead to
an increase in the NAV of the pool.
</Text>
</InlineFeedback>
) : (
<InlineFeedback status="default">
<Text variant="body2" color="statusDefault">
Virtual accounting process. No onchain stablecoin transfers are expected.
</Text>
</InlineFeedback>
)}
</Box>
</Stack>

<Stack>
<Button
type="submit"
loading={isFinanceLoading}
disabled={
!financeForm.values.principal ||
!withdraw.isValid(financeForm) ||
!poolFees.isValid(financeForm) ||
!financeForm.isValid ||
maxAvailable.eq(0)
}
>
{isCashLoan(loan) ? 'Deposit' : 'Finance'}
</Button>
</Stack>
</Form>
</FormikProvider>
)}
</>
Expand Down Expand Up @@ -577,12 +581,11 @@ export function useWithdraw(poolId: string, borrower: CombinedSubstrateAccount,
amount={amount}
/>
),
isValid: (_: { values: Pick<FinanceValues, 'withdraw'> }) => {
isValid: () => {
const withdrawalAddresses = Object.values(selectedAddressIndexByCurrency).filter((index) => index !== -1)
return source === 'reserve' ? amount.lte(totalAvailable) && !!withdrawalAddresses.length : true
},
getBatch: ({ values }: { values: Pick<FinanceValues, 'withdraw'> }) => {
if (!values.withdraw) return of([])
getBatch: () => {
const withdrawalAddresses = Object.values(selectedAddressIndexByCurrency).filter((index) => index !== -1)
if (!withdrawalAddresses.length) return of([])
return combineLatest(
Expand Down

0 comments on commit 33c2114

Please sign in to comment.