Skip to content
Open
81 changes: 27 additions & 54 deletions apps/web/src/app/components/home/CollateralPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Typography } from '@/app/theme';
import IconUnstakeSICX from '@/assets/icons/timer-color.svg';
import IconKeepSICX from '@/assets/icons/wallet-tick-color.svg';
import { NETWORK_ID } from '@/constants/config';
import { SLIDER_RANGE_MAX_BOTTOM_THRESHOLD } from '@/constants/index';
import { MODAL_ID, modalActions } from '@/hooks/useModalStore';
import useWidth from '@/hooks/useWidth';
import { useICXUnstakingTime } from '@/store/application/hooks';
Expand All @@ -31,14 +32,7 @@ import {
useCollateralTokens,
useDerivedCollateralInfo,
useIsHandlingICX,
useSupportedCollateralTokens,
} from '@/store/collateral/hooks';
import {
getActionMaximum,
getSafeSliderBounds,
isCollateralEnabled,
isIncreaseAllowed,
} from '@/store/collateral/eligibility';
import { Field } from '@/store/collateral/reducer';
import { useLoanActionHandlers, useLockedCollateralAmount } from '@/store/loan/hooks';
import { useRatio } from '@/store/ratio/hooks';
Expand Down Expand Up @@ -157,26 +151,6 @@ const CollateralPanel = () => {
const ratio = useRatio();
const isHandlingICX = useIsHandlingICX();
const { data: collateralTokens } = useCollateralTokens();
const { data: supportedCollateralTokens } = useSupportedCollateralTokens();
const contractSymbol = useWrongSymbol(collateralType);
const increaseEnabled = isCollateralEnabled(supportedCollateralTokens, contractSymbol);
const actionMaximum = getActionMaximum(collateralDeposit, collateralTotal, increaseEnabled);
const lockedCollateral = useLockedCollateralAmount();
const shouldShowLock = !lockedCollateral.isZero();

// add small amount of collateral to lock to avoid tx errors.
const tLockedAmount = React.useMemo(
() => BigNumber.min(lockedCollateral.times(shouldShowLock ? 1.005 : 1), collateralDeposit),
[lockedCollateral, collateralDeposit, shouldShowLock],
);
const collateralSliderBounds = getSafeSliderBounds(
collateralDeposit,
actionMaximum,
tLockedAmount,
collateralDecimalPlaces,
);
const canAdjustCollateral = collateralSliderBounds.hasMovableRange;
const percent = collateralTotal.isZero() ? 0 : tLockedAmount.div(collateralTotal).times(100).toNumber();
const [ICXWithdrawOption, setICXWithdrawOption] = useState<ICXWithdrawOptions>(ICXWithdrawOptions.KEEPSICX);
const { data: icxUnstakingTime } = useICXUnstakingTime();
const isSuperSmall = useMedia(`(max-width: 359px)`);
Expand All @@ -203,7 +177,6 @@ const CollateralPanel = () => {
});

const handleEnableAdjusting = () => {
if (!canAdjustCollateral) return;
adjust(true);
adjustLoan(false);
};
Expand All @@ -220,11 +193,6 @@ const CollateralPanel = () => {
const isCrossChain = !(sourceChain === '0x1.icon' || sourceChain === '0x2.icon');

const toggleOpen = () => {
if (open) {
setOpen(false);
return;
}
if (!isIncreaseAllowed(collateralDeposit, parsedAmount[Field.LEFT], increaseEnabled)) return;
if (isCrossChain) {
setStoredModalValues({
amount: `${differenceAmount.dp(collateralDecimalPlaces).toFormat()} ${formatSymbol(collateralType)}`,
Expand All @@ -241,12 +209,9 @@ const CollateralPanel = () => {
const addTransaction = useTransactionAdder();

const handleCollateralConfirm = async () => {
if (shouldDeposit && !increaseEnabled) return;
const collateralTokenAddress = collateralTokens?.[contractSymbol];
if (!collateralTokenAddress) return;

window.addEventListener('beforeunload', showMessageOnBeforeUnload);
const cx = bnJs.inject({ account }).getContract(collateralTokenAddress);
const collateralTokenAddress = collateralTokens && collateralTokens[useWrongSymbol(collateralType)];
const cx = bnJs.inject({ account }).getContract(collateralTokenAddress!);
const decimals: string = await cx.decimals();

if (shouldDeposit) {
Expand Down Expand Up @@ -385,6 +350,17 @@ const CollateralPanel = () => {
);
}, [collateralDecimalPlaces, sliderInstance.current]);

const lockedCollateral = useLockedCollateralAmount();
const shouldShowLock = !lockedCollateral.isZero();

// add small amount of collateral to lock to avoid tx errors.
const tLockedAmount = React.useMemo(
() => BigNumber.min(lockedCollateral.times(shouldShowLock ? 1.005 : 1), collateralTotal),
[lockedCollateral, collateralTotal, shouldShowLock],
);

const percent = collateralTotal.isZero() ? 0 : tLockedAmount.div(collateralTotal).times(100).toNumber();

const hasEnoughICX = useHasEnoughICX();

const [ref, width] = useWidth();
Expand Down Expand Up @@ -414,7 +390,7 @@ const CollateralPanel = () => {
<CollateralTypeSwitcher width={width} containerRef={ref.current} />
</CollateralTypeSwitcherWrap>

{account && collateralTotal?.isGreaterThan(0) && canAdjustCollateral && (
{account && collateralTotal?.isGreaterThan(0) && (
<Flex flexDirection={isSuperSmall ? 'column' : 'row'} ml="auto" paddingTop={isSuperSmall ? '4px' : '0'}>
{isAdjusting ? (
<>
Expand All @@ -426,11 +402,7 @@ const CollateralPanel = () => {
>
<Trans>Cancel</Trans>
</TextButton>
<Button
onClick={toggleOpen}
fontSize={14}
disabled={!isSliderStateChanged || (shouldDeposit && !increaseEnabled)}
>
<Button onClick={toggleOpen} fontSize={14} disabled={!isSliderStateChanged}>
<Trans>Confirm</Trans>
</Button>
</>
Expand Down Expand Up @@ -471,13 +443,17 @@ const CollateralPanel = () => {
<Box pt={7} pb={isAdjusting ? 5 : 6} style={{ transition: 'all ease 0.3s' }}>
<Nouislider
id="slider-collateral"
disabled={!isAdjusting || !collateralSliderBounds.hasMovableRange}
start={collateralSliderBounds.start}
padding={collateralSliderBounds.padding}
disabled={!isAdjusting}
start={collateralDeposit.toNumber()}
padding={[Math.max(tLockedAmount.dp(collateralDecimalPlaces).toNumber(), 0), 0]}
connect={[true, false]}
range={{
min: [0],
max: [collateralSliderBounds.maximum],
max: [
collateralTotal.isZero()
? SLIDER_RANGE_MAX_BOTTOM_THRESHOLD
: collateralTotal.dp(collateralDecimalPlaces).toNumber(),
],
}}
instanceRef={instance => {
if (instance) {
Expand All @@ -498,14 +474,14 @@ const CollateralPanel = () => {
value={formattedAmounts[Field.LEFT]}
decimalPlaces={collateralDecimalPlaces}
currency={isHandlingICX ? 'ICX' : formatSymbol(collateralType)}
maxValue={actionMaximum}
maxValue={collateralTotal}
onUserInput={onFieldAInput}
/>
</PanelInfoItem>

<PanelInfoItem>
<CurrencyField
editable={isAdjusting && increaseEnabled}
editable={isAdjusting}
isActive={false}
label="Wallet"
tooltipText={
Expand Down Expand Up @@ -533,7 +509,6 @@ const CollateralPanel = () => {
<XCollateralModal
account={account}
currencyAmount={xTokenAmount}
increaseEnabled={increaseEnabled}
sourceChain={sourceChain}
storedModalValues={storedModalValues}
/>
Expand Down Expand Up @@ -641,9 +616,7 @@ const CollateralPanel = () => {
onClick={handleCollateralConfirm}
fontSize={14}
disabled={
!hasEnoughICX ||
(shouldDeposit && !increaseEnabled) ||
(isHandlingICX && !shouldDeposit && ICXWithdrawOption === ICXWithdrawOptions.EMPTY)
!hasEnoughICX || (isHandlingICX && !shouldDeposit && ICXWithdrawOption === ICXWithdrawOptions.EMPTY)
}
>
{shouldDeposit ? t`Deposit` : t`Withdraw`}
Expand Down
59 changes: 19 additions & 40 deletions apps/web/src/app/components/home/LoanPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,10 @@ import LockBar from '@/app/components/LockBar';
import Modal from '@/app/components/Modal';
import { BoxPanel, BoxPanelWrap } from '@/app/components/Panel';
import { Typography } from '@/app/theme';
import { SLIDER_RANGE_MAX_BOTTOM_THRESHOLD } from '@/constants/index';
import { useActiveLocale } from '@/hooks/useActiveLocale';
import useInterval from '@/hooks/useInterval';
import {
useCollateralActionHandlers,
useDerivedCollateralInfo,
useSupportedCollateralTokens,
} from '@/store/collateral/hooks';
import {
getActionMaximum,
getSafeSliderBounds,
isCollateralEnabled,
isIncreaseAllowed,
} from '@/store/collateral/eligibility';
import { useCollateralActionHandlers, useDerivedCollateralInfo } from '@/store/collateral/hooks';
import {
useActiveLoanAddress,
useDerivedLoanInfo,
Expand Down Expand Up @@ -65,13 +56,6 @@ const LoanPanel = () => {
totalBorrowableAmount,
bnUSDAmount,
} = useDerivedLoanInfo();
const { data: supportedCollateralTokens } = useSupportedCollateralTokens();
const increaseEnabled = isCollateralEnabled(supportedCollateralTokens, useWrongSymbol(collateralType));
const actionMaximum = getActionMaximum(borrowedAmount, borrowableAmountWithReserve, increaseEnabled);
const activeLoanAccount = useActiveLoanAddress();
const usedAmount = useLoanUsedAmount(activeLoanAccount);
const loanSliderBounds = getSafeSliderBounds(borrowedAmount, actionMaximum, usedAmount, 2);
const canAdjustLoan = loanSliderBounds.hasMovableRange;

const { isAdjusting, inputType } = useLoanState();

Expand Down Expand Up @@ -111,7 +95,6 @@ const LoanPanel = () => {
const addTransaction = useTransactionAdder();

const handleEnableAdjusting = () => {
if (!canAdjustLoan) return;
adjust(true);
adjustCollateral(false);
};
Expand Down Expand Up @@ -141,11 +124,6 @@ const LoanPanel = () => {
(loanNetwork !== ICON_XCALL_NETWORK_ID || sourceChain !== ICON_XCALL_NETWORK_ID);

const toggleOpen = () => {
if (open) {
setOpen(false);
return;
}
if (!isIncreaseAllowed(borrowedAmount, parsedAmount[Field.LEFT], increaseEnabled)) return;
if (isCrossChain) {
setStoredModalValues({
amount: roundedDisplayDiffAmount.dp(2).toFormat(),
Expand All @@ -161,7 +139,6 @@ const LoanPanel = () => {
};

const handleLoanConfirm = () => {
if (shouldBorrow && !increaseEnabled) return;
if (!iconAccount) return;
window.addEventListener('beforeunload', showMessageOnBeforeUnload);

Expand Down Expand Up @@ -241,6 +218,8 @@ const LoanPanel = () => {

const roundedDisplayDiffAmount = parsedAmount[Field.LEFT].minus(borrowedAmount.dp(2));

const activeLoanAccount = useActiveLoanAddress();
const usedAmount = useLoanUsedAmount(activeLoanAccount);
const percent = borrowableAmountWithReserve.isZero()
? 0
: usedAmount.div(borrowableAmountWithReserve).times(100).toNumber();
Expand Down Expand Up @@ -282,7 +261,7 @@ const LoanPanel = () => {
<Typography variant="h2">
<Trans>Loan</Trans>
</Typography>
{account && canAdjustLoan && (
{account && (
<Flex flexDirection={isSuperSmall ? 'column' : 'row'} paddingTop={isSuperSmall ? '4px' : '0'}>
{isAdjusting ? (
<>
Expand All @@ -297,7 +276,6 @@ const LoanPanel = () => {
<Button
disabled={
!isSliderStateChanged ||
(shouldBorrow && !increaseEnabled) ||
(borrowedAmount.isLessThanOrEqualTo(0)
? currentValue >= 0 && currentValue < 10
: currentValue < 0)
Expand All @@ -321,15 +299,23 @@ const LoanPanel = () => {

<Box pt={7} pb={isAdjusting ? 5 : 6} style={{ transition: 'all ease 0.3s' }}>
<Nouislider
disabled={!isAdjusting || !loanSliderBounds.hasMovableRange}
disabled={!isAdjusting}
id="slider-loan"
start={[loanSliderBounds.start]}
padding={loanSliderBounds.padding}
start={[borrowedAmount.dp(2).toNumber()]}
padding={[
Math.max(Math.min(usedAmount.dp(2).toNumber(), borrowableAmountWithReserve.dp(2).toNumber()), 0),
0,
]}
connect={[true, false]}
range={{
min: [0],
// https://github.com/balancednetwork/balanced-network-interface/issues/50
max: [loanSliderBounds.maximum],
max: [
Number.isNaN(borrowableAmountWithReserve.dp(2).toNumber()) ||
borrowableAmountWithReserve.dp(2).isZero()
? SLIDER_RANGE_MAX_BOTTOM_THRESHOLD
: borrowableAmountWithReserve.dp(2).toNumber(),
],
}}
instanceRef={instance => {
if (instance) {
Expand All @@ -351,7 +337,6 @@ const LoanPanel = () => {
noticeText={'10 bnUSD minimum'}
value={formattedAmounts[Field.LEFT]}
currency={'bnUSD'}
maxValue={actionMaximum}
onUserInput={onFieldAInput}
/>
) : (
Expand All @@ -362,15 +347,14 @@ const LoanPanel = () => {
tooltipText="Your collateral balance. It earns interest from staking, but is also sold over time to repay your loan."
value={formattedAmounts[Field.LEFT]}
currency={'bnUSD'}
maxValue={actionMaximum}
onUserInput={onFieldAInput}
/>
)}
</PanelInfoItem>

<PanelInfoItem>
<CurrencyField
editable={isAdjusting && increaseEnabled}
editable={isAdjusting}
isActive={false}
label="Available"
tooltipText="The amount of ICX available to deposit from your wallet."
Expand All @@ -391,7 +375,6 @@ const LoanPanel = () => {
<XLoanModal
collateralAccount={account}
bnUSDAmount={bnUSDAmount}
increaseEnabled={increaseEnabled}
sourceChain={sourceChain}
interestRate={interestRate}
storedModalValues={storedModalValues}
Expand Down Expand Up @@ -447,11 +430,7 @@ const LoanPanel = () => {
<TextButton onClick={toggleOpen} fontSize={14}>
<Trans>Cancel</Trans>
</TextButton>
<Button
disabled={!hasEnoughICX || (shouldBorrow && !increaseEnabled)}
onClick={handleLoanConfirm}
fontSize={14}
>
<Button disabled={!hasEnoughICX} onClick={handleLoanConfirm} fontSize={14}>
<Trans>{shouldBorrow ? t`Borrow` : t`Repay`}</Trans>
</Button>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export enum XCollateralAction {
type XCollateralModalProps = {
modalId?: MODAL_ID;
account: string | undefined;
increaseEnabled: boolean;
sourceChain: XChainId;
storedModalValues: {
amount: string;
Expand All @@ -49,7 +48,6 @@ const XCollateralModal = ({
modalId = MODAL_ID.XCOLLATERAL_CONFIRM_MODAL,
account,
currencyAmount,
increaseEnabled,
sourceChain,
storedModalValues,
}: XCollateralModalProps) => {
Expand Down Expand Up @@ -104,7 +102,6 @@ const XCollateralModal = ({

const sendXTransaction = useSendXTransaction();
const handleXCollateralAction = async () => {
if (storedModalValues.action === XCollateralAction.DEPOSIT && !increaseEnabled) return;
if (!account) return;
if (!xCallFee) return;
if (!_inputAmount) return;
Expand Down Expand Up @@ -143,7 +140,6 @@ const XCollateralModal = ({

useLoanWalletServiceHandler();
const { isWrongChain, handleSwitchChain } = useEvmSwitchChain(sourceChain);
const increaseDisabled = storedModalValues.action === XCollateralAction.DEPOSIT && !increaseEnabled;

return (
<>
Expand Down Expand Up @@ -220,10 +216,7 @@ const XCollateralModal = ({
) : (
<>
{approvalState !== ApprovalState.APPROVED ? (
<Button
onClick={approveCallback}
disabled={approvalState === ApprovalState.PENDING || increaseDisabled}
>
<Button onClick={approveCallback} disabled={approvalState === ApprovalState.PENDING}>
{approvalState === ApprovalState.PENDING ? (
<Trans>Approving</Trans>
) : (
Expand All @@ -233,7 +226,7 @@ const XCollateralModal = ({
) : (
<StyledButton
onClick={handleXCollateralAction}
disabled={!gasChecker.hasEnoughGas || isWalletPrompting || increaseDisabled}
disabled={!gasChecker.hasEnoughGas || isWalletPrompting}
>
{isWalletPrompting ? (
<Trans>Waiting for wallet...</Trans>
Expand Down
Loading