forked from DistributedCollective/sovryn-dapp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from wakeuplabs-io/SAF-10_borrow-components
SAF-10 Implement borrow components
- Loading branch information
Showing
6 changed files
with
296 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
219 changes: 219 additions & 0 deletions
219
...rc/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
import React, { FC, useCallback, useMemo, useState } from 'react'; | ||
|
||
import { t } from 'i18next'; | ||
|
||
import { | ||
AmountInput, | ||
Button, | ||
Checkbox, | ||
ErrorBadge, | ||
ErrorLevel, | ||
HealthBar, | ||
Link, | ||
Paragraph, | ||
ParagraphSize, | ||
Select, | ||
SimpleTable, | ||
SimpleTableRow, | ||
} from '@sovryn/ui'; | ||
import { Decimal } from '@sovryn/utils'; | ||
|
||
import { AmountRenderer } from '../../../../../../2_molecules/AmountRenderer/AmountRenderer'; | ||
import { AssetRenderer } from '../../../../../../2_molecules/AssetRenderer/AssetRenderer'; | ||
import { useDecimalAmountInput } from '../../../../../../../hooks/useDecimalAmountInput'; | ||
import { translations } from '../../../../../../../locales/i18n'; | ||
import { getCollateralRatioThresholds } from './BorrowForm.utils'; | ||
|
||
const pageTranslations = translations.aavePage; | ||
|
||
type BorrowFormProps = { | ||
onSuccess: () => unknown; | ||
}; | ||
|
||
export const BorrowForm: FC<BorrowFormProps> = () => { | ||
const assetPrice = 3258.47; // TODO: this is mocked data. Replace with proper hook | ||
const totalBorrow = Decimal.from(10); // TODO: this is mocked data. Replace with proper hook | ||
const collateralToLoanRate = Decimal.from(10); // TODO: this is mocked data. Replace with proper hook | ||
const collateralSize = Decimal.from(10); // TODO: this is mockd data. Replace with proper hook | ||
const borrowableAssets = useMemo(() => ['BTC', 'SOV'], []); // TODO: this is mocked data. Replace with proper hook | ||
const [maximumBorrowAmount] = useState<Decimal>(Decimal.from(10)); // TODO: this is mocked data. Replace with proper hook | ||
const [borrowAsset, setBorrowAsset] = useState<string>(borrowableAssets[0]); | ||
const [borrowAmount, setBorrowAmount, borrowSize] = useDecimalAmountInput(''); | ||
const [acknowledge, setAcknowledge] = useState<boolean>(false); | ||
|
||
const onBorrowAssetChange = useCallback(v => { | ||
setBorrowAsset(v); | ||
}, []); | ||
|
||
const borrowableAssetsOptions = useMemo( | ||
() => | ||
borrowableAssets.map(token => ({ | ||
value: token, | ||
label: ( | ||
<AssetRenderer | ||
showAssetLogo | ||
asset={token} | ||
assetClassName="font-medium" | ||
/> | ||
), | ||
})), | ||
[borrowableAssets], | ||
); | ||
|
||
const isValidBorrowAmount = useMemo( | ||
() => (borrowSize.gt(0) ? borrowSize.lte(maximumBorrowAmount) : true), | ||
[borrowSize, maximumBorrowAmount], | ||
); | ||
|
||
const remainingSupply = useMemo( | ||
() => maximumBorrowAmount.sub(borrowSize), | ||
[borrowSize, maximumBorrowAmount], | ||
); | ||
|
||
const collateralRatioThresholds = useMemo( | ||
() => getCollateralRatioThresholds(), | ||
[], | ||
); | ||
|
||
const collateralRatio = useMemo(() => { | ||
if ([collateralSize, totalBorrow, borrowSize].some(v => v.isZero())) { | ||
return Decimal.ZERO; | ||
} | ||
|
||
return collateralSize.mul(collateralToLoanRate).div(totalBorrow).mul(100); | ||
}, [collateralSize, totalBorrow, borrowSize, collateralToLoanRate]); | ||
|
||
const submitButtonDisabled = useMemo( | ||
() => !isValidBorrowAmount || borrowSize.lte(0) || !acknowledge, | ||
[isValidBorrowAmount, borrowSize, acknowledge], | ||
); | ||
|
||
return ( | ||
<form className="flex flex-col gap-6"> | ||
<div className="space-y-3"> | ||
<div className="flex justify-between items-end"> | ||
<Paragraph size={ParagraphSize.base} className="font-medium"> | ||
{t(translations.aavePage.common.borrow)} | ||
</Paragraph> | ||
|
||
<span className="text-xs underline"> | ||
(Max{' '} | ||
<AmountRenderer | ||
value={maximumBorrowAmount} | ||
suffix={borrowAsset} | ||
prefix="~" | ||
/> | ||
) | ||
</span> | ||
</div> | ||
|
||
<div> | ||
<div className="flex space-x-3"> | ||
<div className="text-right flex-grow space-y-1"> | ||
<AmountInput | ||
label={t(translations.common.amount)} | ||
value={borrowAmount} | ||
onChangeText={setBorrowAmount} | ||
placeholder="0" | ||
invalid={!isValidBorrowAmount} | ||
/> | ||
<div className=" pr-4"> | ||
<AmountRenderer | ||
className="text-gray-40" | ||
value={0} // TODO: usd equivalent | ||
prefix="$" | ||
/> | ||
</div> | ||
</div> | ||
|
||
<Select | ||
value={borrowAsset} | ||
onChange={onBorrowAssetChange} | ||
options={borrowableAssetsOptions} | ||
labelRenderer={({ value }) => ( | ||
<AssetRenderer | ||
dataAttribute="borrow-asset-asset" | ||
showAssetLogo | ||
asset={value} | ||
/> | ||
)} | ||
className="min-w-[6.7rem]" | ||
menuClassName="max-h-[10rem] sm:max-h-[20rem]" | ||
dataAttribute="borrow-asset-select" | ||
/> | ||
</div> | ||
</div> | ||
<div> | ||
{!isValidBorrowAmount && ( | ||
<ErrorBadge | ||
level={ErrorLevel.Critical} | ||
message={t(pageTranslations.borrowForm.invalidAmountError)} | ||
dataAttribute="borrow-amount-error" | ||
/> | ||
)} | ||
</div> | ||
</div> | ||
|
||
<SimpleTable> | ||
<SimpleTableRow | ||
label={t(translations.aavePage.borrowForm.borrowApr)} | ||
value={ | ||
<AmountRenderer | ||
value={remainingSupply.toNumber()} | ||
suffix={borrowAsset} | ||
/> | ||
} | ||
/> | ||
</SimpleTable> | ||
|
||
<div> | ||
<div className="flex flex-row justify-between items-center mt-6 mb-3"> | ||
<div className="flex flex-row justify-start items-center gap-2"> | ||
<span>{t(translations.aavePage.borrowForm.collateralRatio)}</span> | ||
</div> | ||
<div className=""> | ||
<AmountRenderer value={collateralRatio.toString()} suffix="%" /> | ||
</div> | ||
</div> | ||
|
||
<HealthBar | ||
start={collateralRatioThresholds.START} | ||
middleStart={collateralRatioThresholds.MIDDLE_START} | ||
middleEnd={collateralRatioThresholds.MIDDLE_END} | ||
end={collateralRatioThresholds.END} | ||
value={collateralRatio.toNumber()} | ||
/> | ||
</div> | ||
|
||
<SimpleTable> | ||
<SimpleTableRow | ||
label={t(translations.aavePage.borrowForm.liquidationPrice)} | ||
value={t(translations.aavePage.common['n/a'])} | ||
/> | ||
<SimpleTableRow | ||
label={t(translations.aavePage.borrowForm.tokenPrice, { | ||
token: borrowAsset, | ||
})} | ||
value={<AmountRenderer value={assetPrice} prefix={'$'} />} | ||
/> | ||
</SimpleTable> | ||
|
||
<Checkbox | ||
checked={acknowledge} | ||
onChangeValue={setAcknowledge} | ||
label={ | ||
<span> | ||
{t(translations.aavePage.borrowForm.acknowledge)}{' '} | ||
<Link text="Learn more" href="#learn-more" />{' '} | ||
{/* TODO: Add proper learn more href */} | ||
</span> | ||
} | ||
/> | ||
|
||
<Button | ||
disabled={submitButtonDisabled} | ||
text={t(translations.common.buttons.confirm)} | ||
/> | ||
</form> | ||
); | ||
}; |
14 changes: 14 additions & 0 deletions
14
...p/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { MINIMUM_COLLATERAL_RATIO_LENDING_POOLS } from '../../../../../../../constants/lending'; | ||
|
||
export const getCollateralRatioThresholds = () => { | ||
// TODO: recheck this and adjust based on aave | ||
const minimumCollateralRatio = | ||
MINIMUM_COLLATERAL_RATIO_LENDING_POOLS.mul(100); | ||
|
||
return { | ||
START: minimumCollateralRatio.mul(0.9).toNumber(), | ||
MIDDLE_START: minimumCollateralRatio.toNumber() - 0.1, | ||
MIDDLE_END: minimumCollateralRatio.mul(1.2).toNumber(), | ||
END: minimumCollateralRatio.mul(1.6).toNumber(), | ||
}; | ||
}; |
30 changes: 30 additions & 0 deletions
30
...ages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowModalContainer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import React, { FC } from 'react'; | ||
|
||
import { t } from 'i18next'; | ||
|
||
import { Dialog, DialogBody, DialogHeader } from '@sovryn/ui'; | ||
|
||
import { translations } from '../../../../../../../locales/i18n'; | ||
import { BorrowForm } from './BorrowForm'; | ||
|
||
type BorrowModalContainerProps = { | ||
isOpen: boolean; | ||
handleCloseModal: () => unknown; | ||
}; | ||
|
||
export const BorrowModalContainer: FC<BorrowModalContainerProps> = ({ | ||
isOpen, | ||
handleCloseModal, | ||
}) => { | ||
return ( | ||
<Dialog disableFocusTrap isOpen={isOpen}> | ||
<DialogHeader | ||
title={t(translations.aavePage.common.borrow)} | ||
onClose={handleCloseModal} | ||
/> | ||
<DialogBody className="flex flex-col gap-6"> | ||
<BorrowForm onSuccess={handleCloseModal} /> | ||
</DialogBody> | ||
</Dialog> | ||
); | ||
}; |
2 changes: 1 addition & 1 deletion
2
...avePage/components/LendPositionsList/components/LendPositionAction/LendPositionAction.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters