Mp 2881 finalize the borrow flow table (#308)

* MP-2881: fixed the buttons and adjusted the marketDetails

* MP-2881: finished the borrow to wallet functionatlity

* fix: renamed withdraw to borrowToWallet

* fix: moved the useMemo return into functions

* tidy: refactor

* tidy: refactor
This commit is contained in:
Linkie Link 2023-07-19 12:10:23 +02:00 committed by GitHub
parent e1956ddbe9
commit ac0658224e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 149 additions and 102 deletions

View File

@ -1,7 +1,7 @@
import { useCallback } from 'react'
import Button from 'components/Button'
import { Plus } from 'components/Icons'
import { Plus, ReceiptCheck } from 'components/Icons'
import useStore from 'store'
import { getEnabledMarketAssets } from 'utils/assets'
@ -29,13 +29,15 @@ export default function BorrowActionButtons(props: Props) {
return (
<div className='flex flex-row space-x-2'>
<Button
leftIcon={debt ? <Plus /> : undefined}
leftIcon={<Plus className='w-3' />}
onClick={borrowHandler}
color='secondary'
text={debt ? 'Borrow more' : 'Borrow'}
className='min-w-40 text-center'
/>
{debt && <Button color='secondary' text='Repay' onClick={repayHandler} />}
{debt && (
<Button color='tertiary' leftIcon={<ReceiptCheck />} text='Repay' onClick={repayHandler} />
)}
</div>
)
}

View File

@ -33,7 +33,7 @@ export default function BorrowTable(props: Props) {
resetExpanded={table.resetExpanded}
rowData={row}
expandedActionButtons={<BorrowActionButtons data={row.original} />}
expandedDetails={<MarketDetails data={row.original} />}
expandedDetails={<MarketDetails data={row.original} type='borrow' />}
/>
)
},

View File

@ -32,7 +32,7 @@ export default function LendingMarketsTable(props: Props) {
resetExpanded={table.resetExpanded}
rowData={row}
expandedActionButtons={<LendingActionButtons data={row.original} />}
expandedDetails={<MarketDetails data={row.original} />}
expandedDetails={<MarketDetails data={row.original} type='lend' />}
/>
)
},

View File

@ -0,0 +1,8 @@
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M5.99984 7L7.33317 8.33333L10.3332 5.33333M13.3332 14V5.2C13.3332 4.0799 13.3332 3.51984 13.1152 3.09202C12.9234 2.71569 12.6175 2.40973 12.2412 2.21799C11.8133 2 11.2533 2 10.1332 2H5.8665C4.7464 2 4.18635 2 3.75852 2.21799C3.3822 2.40973 3.07624 2.71569 2.88449 3.09202C2.6665 3.51984 2.6665 4.0799 2.6665 5.2V14L4.49984 12.6667L6.1665 14L7.99984 12.6667L9.83317 14L11.4998 12.6667L13.3332 14Z"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>

After

Width:  |  Height:  |  Size: 578 B

View File

@ -31,6 +31,7 @@ export { default as OverlayMark } from 'components/Icons/OverlayMark.svg'
export { default as Plus } from 'components/Icons/Plus.svg'
export { default as PlusCircled } from 'components/Icons/PlusCircled.svg'
export { default as Questionmark } from 'components/Icons/Questionmark.svg'
export { default as ReceiptCheck } from 'components/Icons/ReceiptCheck.svg'
export { default as Search } from 'components/Icons/Search.svg'
export { default as Shield } from 'components/Icons/Shield.svg'
export { default as SortAsc } from 'components/Icons/SortAsc.svg'
@ -41,6 +42,6 @@ export { default as StarOutlined } from 'components/Icons/StarOutlined.svg'
export { default as Subtract } from 'components/Icons/Subtract.svg'
export { default as SwapIcon } from 'components/Icons/SwapIcon.svg'
export { default as TrashBin } from 'components/Icons/TrashBin.svg'
export { default as Wallet } from 'components/Icons/Wallet.svg'
export { default as VerticalThreeLine } from 'components/Icons/VerticalThreeLine.svg'
export { default as Wallet } from 'components/Icons/Wallet.svg'
// @endindex

View File

@ -6,6 +6,7 @@ import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
interface Props {
data: BorrowMarketTableData | LendingMarketTableData
type: 'borrow' | 'lend'
}
interface Detail {
@ -14,12 +15,13 @@ interface Detail {
title: string
}
export default function MarketDetails({ data }: Props) {
export default function MarketDetails({ data, type }: Props) {
const {
convertAmount,
getConversionRate,
symbol: displayCurrencySymbol,
} = useDisplayCurrencyPrice()
const {
asset,
marketMaxLtv,
@ -30,48 +32,73 @@ export default function MarketDetails({ data }: Props) {
const totalBorrowed = marketDepositAmount.minus(marketLiquidityAmount)
const details: Detail[] = useMemo(
() => [
{
amount: convertAmount(asset, marketDepositAmount).toNumber(),
options: { abbreviated: true, suffix: ` ${displayCurrencySymbol}` },
title: 'Total Supplied',
},
{
amount: marketMaxLtv * 100,
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
title: 'Max LTV',
},
{
amount: marketLiquidationThreshold * 100,
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
title: 'Liquidation Threshold',
},
{
amount: getConversionRate(asset.denom).toNumber(),
options: { minDecimals: 2, maxDecimals: 2, suffix: ` ${displayCurrencySymbol}` },
title: 'Oracle Price',
},
{
amount: totalBorrowed.dividedBy(marketDepositAmount).multipliedBy(100).toNumber(),
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
title: 'Utilization Rate',
},
],
[
asset,
marketDepositAmount,
marketLiquidationThreshold,
marketMaxLtv,
displayCurrencySymbol,
convertAmount,
getConversionRate,
totalBorrowed,
],
)
const details: Detail[] = useMemo(() => {
function getLendingMarketDetails() {
return [
{
amount: convertAmount(asset, marketDepositAmount).toNumber(),
options: { abbreviated: true, suffix: ` ${displayCurrencySymbol}` },
title: 'Total Supplied',
},
{
amount: marketMaxLtv * 100,
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
title: 'Max LTV',
},
{
amount: marketLiquidationThreshold * 100,
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
title: 'Liquidation Threshold',
},
{
amount: getConversionRate(asset.denom).toNumber(),
options: { minDecimals: 2, maxDecimals: 2, suffix: ` ${displayCurrencySymbol}` },
title: 'Oracle Price',
},
{
amount: totalBorrowed.dividedBy(marketDepositAmount).multipliedBy(100).toNumber(),
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
title: 'Utilization Rate',
},
]
}
function getBorrowMarketDetails() {
return [
{
amount: convertAmount(asset, totalBorrowed).toNumber(),
options: { abbreviated: true, suffix: ` ${displayCurrencySymbol}` },
title: 'Total Borrowed',
},
{
amount: getConversionRate(asset.denom).toNumber(),
options: { minDecimals: 2, maxDecimals: 2, suffix: ` ${displayCurrencySymbol}` },
title: 'Oracle Price',
},
{
amount: totalBorrowed.dividedBy(marketDepositAmount).multipliedBy(100).toNumber(),
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
title: 'Utilization Rate',
},
]
}
if (type === 'lend') return getLendingMarketDetails()
return getBorrowMarketDetails()
}, [
type,
asset,
marketDepositAmount,
marketMaxLtv,
marketLiquidationThreshold,
totalBorrowed,
displayCurrencySymbol,
convertAmount,
getConversionRate,
])
return (
<div className='flex flex-1 justify-center rounded-md bg-white bg-opacity-5'>
<div className='flex flex-1 justify-between rounded-md bg-white bg-opacity-5'>
{details.map((detail, index) => (
<TitleAndSubCell
key={index}

View File

@ -7,7 +7,7 @@ import Card from 'components/Card'
import Divider from 'components/Divider'
import { ArrowRight } from 'components/Icons'
import Modal from 'components/Modal'
import Select from 'components/Select'
import Switch from 'components/Switch'
import Text from 'components/Text'
import TitleAndSubCell from 'components/TitleAndSubCell'
import TokenInputWithSlider from 'components/TokenInputWithSlider'
@ -34,16 +34,12 @@ export default function BorrowModal() {
const [percentage, setPercentage] = useState(0)
const [amount, setAmount] = useState(BN(0))
const [change, setChange] = useState<AccountChange | undefined>()
const [selectedAccount, setSelectedAccount] = useState(currentAccount)
const [isConfirming, setIsConfirming] = useToggle()
const [borrowToWallet, setBorrowToWallet] = useToggle()
const modal = useStore((s) => s.borrowModal)
const borrow = useStore((s) => s.borrow)
const repay = useStore((s) => s.repay)
const asset = modal?.asset ?? ASSETS[0]
const accounts = useStore((s) => s.accounts)
const accountOptions = accounts?.map((account) => {
return { value: account.id, label: `Account ${account.id}` }
})
const isRepay = modal?.isRepay ?? false
function resetState() {
@ -53,21 +49,22 @@ export default function BorrowModal() {
}
async function onConfirmClick() {
if (!modal?.asset) return
if (!modal?.asset || !currentAccount) return
setIsConfirming(true)
let result
if (isRepay) {
result = await repay({
fee: hardcodedFee,
accountId: selectedAccount?.id ?? '0',
accountId: currentAccount.id,
coin: BNCoin.fromDenomAndBigNumber(modal.asset.denom, amount),
accountBalance: percentage === 100,
})
} else {
result = await borrow({
fee: hardcodedFee,
accountId: selectedAccount?.id ?? '0',
accountId: currentAccount.id,
coin: { denom: modal.asset.denom, amount: amount.toString() },
borrowToWallet,
})
}
@ -95,10 +92,6 @@ export default function BorrowModal() {
const max = BN(isRepay ? getDebtAmount(modal) : modal?.marketData?.liquidity?.amount ?? '0')
useEffect(() => {
if (!selectedAccount) setSelectedAccount(currentAccount)
}, [selectedAccount, currentAccount])
useEffect(() => {
if (!modal?.asset) return
@ -167,19 +160,17 @@ export default function BorrowModal() {
maxText='Max'
/>
<Divider className='my-6' />
<Text size='lg' className='pb-2'>
{isRepay ? 'Repay for' : 'Borrow to'}
</Text>
<div className='relative flex w-full'>
<Select
options={accountOptions ?? []}
title='Accounts'
defaultValue={selectedAccount?.id}
containerClassName='w-full'
onChange={(account) => {
accounts && setSelectedAccount(accounts?.find((a) => a.id === account))
}}
className='w-full rounded-base border border-white/10 bg-white/5'
<div className='flex flex-1 flex-wrap'>
<Text className='mb-1 w-full'>Receive funds to Wallet</Text>
<Text size='xs' className='text-white/50'>
Your borrowed funds will directly go to your wallet
</Text>
</div>
<div className='flex flex-wrap items-center justify-end'>
<Switch
name='borrow-to-wallet'
checked={borrowToWallet}
onChange={setBorrowToWallet}
/>
</div>
</div>
@ -192,7 +183,7 @@ export default function BorrowModal() {
rightIcon={<ArrowRight />}
/>
</Card>
<AccountSummary account={selectedAccount} change={change} />
<AccountSummary account={currentAccount} change={change} />
</div>
</Modal>
)

View File

@ -42,11 +42,20 @@ export default function createBroadcastSlice(
return {
toast: null,
borrow: async (options: { fee: StdFee; accountId: string; coin: Coin }) => {
borrow: async (options: {
fee: StdFee
accountId: string
coin: Coin
borrowToWallet: boolean
}) => {
const borrowAction: Action = { borrow: options.coin }
const withdrawAction: Action = { withdraw: options.coin }
const actions = options.borrowToWallet ? [borrowAction, withdrawAction] : [borrowAction]
const msg: CreditManagerExecuteMsg = {
update_credit_account: {
account_id: options.accountId,
actions: [{ borrow: options.coin }],
actions,
},
}
@ -54,7 +63,9 @@ export default function createBroadcastSlice(
handleResponseMessages(
response,
`Borrowed ${formatAmountWithSymbol(options.coin)} to Account ${options.accountId}`,
`Borrowed ${formatAmountWithSymbol(options.coin)} to ${
options.borrowToWallet ? 'Wallet' : `Account ${options.accountId}`
}`,
)
return !!response.result
},

View File

@ -5,25 +5,26 @@
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult } from '@cosmjs/cosmwasm-stargate'
import { CosmWasmClient, ExecuteResult, SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import { Coin, StdFee } from '@cosmjs/amino'
import {
InstantiateMsg,
ExecuteMsg,
OsmosisPriceSourceForString,
ArrayOfPriceResponse,
ArrayOfPriceSourceResponseForString,
ConfigResponse,
Decimal,
Downtime,
Identifier,
OwnerUpdate,
DowntimeDetector,
ExecuteMsg,
GeometricTwap,
RedemptionRateForString,
QueryMsg,
ConfigResponse,
Identifier,
InstantiateMsg,
OsmosisPriceSourceForString,
OwnerUpdate,
PriceResponse,
PriceSourceResponseForString,
ArrayOfPriceSourceResponseForString,
ArrayOfPriceResponse,
QueryMsg,
RedemptionRateForString,
} from './MarsOracleOsmosis.types'
export interface MarsOracleOsmosisReadOnlyInterface {
contractAddress: string

View File

@ -5,28 +5,29 @@
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
import { UseQueryOptions, useQuery, useMutation, UseMutationOptions } from '@tanstack/react-query'
import { useMutation, UseMutationOptions, useQuery, UseQueryOptions } from '@tanstack/react-query'
import { ExecuteResult } from '@cosmjs/cosmwasm-stargate'
import { StdFee, Coin } from '@cosmjs/amino'
import { Coin, StdFee } from '@cosmjs/amino'
import {
InstantiateMsg,
ExecuteMsg,
OsmosisPriceSourceForString,
ArrayOfPriceResponse,
ArrayOfPriceSourceResponseForString,
ConfigResponse,
Decimal,
Downtime,
Identifier,
OwnerUpdate,
DowntimeDetector,
ExecuteMsg,
GeometricTwap,
RedemptionRateForString,
QueryMsg,
ConfigResponse,
Identifier,
InstantiateMsg,
OsmosisPriceSourceForString,
OwnerUpdate,
PriceResponse,
PriceSourceResponseForString,
ArrayOfPriceSourceResponseForString,
ArrayOfPriceResponse,
QueryMsg,
RedemptionRateForString,
} from './MarsOracleOsmosis.types'
import { MarsOracleOsmosisQueryClient, MarsOracleOsmosisClient } from './MarsOracleOsmosis.client'
import { MarsOracleOsmosisClient, MarsOracleOsmosisQueryClient } from './MarsOracleOsmosis.client'
export const marsOracleOsmosisQueryKeys = {
contract: [
{

View File

@ -12,7 +12,12 @@ interface BroadcastSlice {
fee: StdFee
funds?: Coin[]
}) => Promise<BroadcastResult>
borrow: (options: { fee: StdFee; accountId: string; coin: Coin }) => Promise<boolean>
borrow: (options: {
fee: StdFee
accountId: string
coin: Coin
borrowToWallet: boolean
}) => Promise<boolean>
createAccount: (options: { fee: StdFee }) => Promise<string | null>
deleteAccount: (options: { fee: StdFee; accountId: string }) => Promise<boolean>
deposit: (options: { fee: StdFee; accountId: string; coin: Coin }) => Promise<boolean>