Mp depostied vaults table (#271)

* added correct resolving of account positions

* solve rendering bug for lp amount

* bugfix: add slippage to minlpamount

* fix DisplayCurrency to accept only BNCoin

* bugfix: remove prices from store

* add basic depostied vaults table

* Farm: Added deposited table

* finish deposited table, remove featured vaults:
This commit is contained in:
Bob van der Helm 2023-06-29 12:55:47 +02:00 committed by GitHub
parent 9007e31707
commit 697e83b7cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 309 additions and 233 deletions

View File

@ -6,6 +6,7 @@ import useStore from 'store'
import DisplayCurrency from 'components/DisplayCurrency'
import VaultBorrowings, { VaultBorrowingsProps } from 'components/Modals/Vault/VaultBorrowings'
import { TESTNET_VAULTS_META_DATA } from 'constants/vaults'
import { BNCoin } from 'types/classes/BNCoin'
jest.mock('hooks/usePrices', () =>
jest.fn(() => ({
@ -38,8 +39,8 @@ const mockedVault: Vault = {
},
cap: {
denom: 'test',
max: 10,
used: 2,
max: BN(10),
used: BN(2),
},
}
describe('<VaultBorrowings />', () => {
@ -80,7 +81,7 @@ describe('<VaultBorrowings />', () => {
it('should render DisplayCurrency correctly', () => {
expect(mockedDisplayCurrency).toHaveBeenCalledTimes(1)
expect(mockedDisplayCurrency).toHaveBeenCalledWith(
{ coin: { denom: 'uosmo', amount: '0' } },
{ coin: new BNCoin({ denom: 'uosmo', amount: '0' }) },
expect.anything(),
)
})

View File

@ -1,6 +1,7 @@
import { getCreditManagerQueryClient } from 'api/cosmwasm-client'
import { BNCoin } from 'types/classes/BNCoin'
import { Positions } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
import { resolvePositionResponse } from 'utils/resolvers'
export default async function getAccount(accountId: string): Promise<Account> {
const creditManagerQueryClient = await getCreditManagerQueryClient()
@ -8,17 +9,7 @@ export default async function getAccount(accountId: string): Promise<Account> {
const accountPosition: Positions = await creditManagerQueryClient.positions({ accountId })
if (accountPosition) {
const debts = accountPosition.debts.map((debt) => new BNCoin(debt))
const lends = accountPosition.lends.map((lend) => new BNCoin(lend))
const deposits = accountPosition.deposits.map((deposit) => new BNCoin(deposit))
return {
id: accountPosition.account_id,
debts,
deposits,
lends,
vaults: accountPosition.vaults,
}
return resolvePositionResponse(accountPosition)
}
return new Promise((_, reject) => reject('No account found'))

View File

@ -2,8 +2,12 @@ import { getCreditManagerQueryClient } from 'api/cosmwasm-client'
import { ENV } from 'constants/env'
import { BN } from 'utils/helpers'
export default async function getVaultConfigs(coins: Coin[], lpDenom: string): Promise<BigNumber> {
if (!ENV.ADDRESS_CREDIT_MANAGER) return BN(0)
export default async function getVaultConfigs(
coins: Coin[],
lpDenom: string,
slippage: number,
): Promise<BigNumber> {
if (!ENV.ADDRESS_CREDIT_MANAGER) return BN(Infinity)
const creditManagerQueryClient = await getCreditManagerQueryClient()
try {
@ -13,6 +17,8 @@ export default async function getVaultConfigs(coins: Coin[], lpDenom: string): P
lpTokenOut: lpDenom,
}),
)
.times(1 - slippage)
.integerValue()
} catch (ex) {
throw ex
}

View File

@ -4,6 +4,7 @@ import { getVaultConfigs } from 'api/vaults/getVaultConfigs'
import { getVaultUtilizations } from 'api/vaults/getVaultUtilizations'
import { ENV } from 'constants/env'
import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults'
import { BN } from 'utils/helpers'
export default async function getVaults(): Promise<Vault[]> {
const vaultConfigs = await getVaultConfigs([])
@ -24,12 +25,12 @@ export default async function getVaults(): Promise<Vault[]> {
const vault: Vault = {
...vaultMetaData,
cap: {
max: Number(vaultConfig.deposit_cap.amount),
max: BN(vaultConfig.deposit_cap.amount),
denom: vaultConfig.deposit_cap.denom,
used: Number(
used: BN(
vaultUtilizations.find(
(vaultUtilization) => vaultUtilization.vault.address === vaultConfig.addr,
) || 0,
)?.utilization.amount || 0,
),
},
apy: apr ? convertAprToApy(apr.apr, 365) : null,

View File

@ -17,6 +17,8 @@ import { ASSETS } from 'constants/assets'
import useStore from 'store'
import { convertToDisplayAmount, demagnify } from 'utils/formatters'
import { BN } from 'utils/helpers'
import { BNCoin } from 'types/classes/BNCoin'
import usePrices from 'hooks/usePrices'
interface Props {
data: Account
@ -24,7 +26,8 @@ interface Props {
export const AccountBalancesTable = (props: Props) => {
const displayCurrency = useStore((s) => s.displayCurrency)
const prices = useStore((s) => s.prices)
const { data: prices } = usePrices()
const [sorting, setSorting] = React.useState<SortingState>([])
const balanceData = React.useMemo<AccountBalanceRow[]>(() => {
@ -41,7 +44,7 @@ export const AccountBalancesTable = (props: Props) => {
amount: deposit.amount,
size: demagnify(deposit.amount, asset),
value: convertToDisplayAmount(
{ amount: deposit.amount, denom: deposit.denom },
new BNCoin({ amount: deposit.amount, denom: deposit.denom }),
displayCurrency,
prices,
).toString(),
@ -58,7 +61,7 @@ export const AccountBalancesTable = (props: Props) => {
amount: lending.amount,
size: demagnify(lending.amount, asset),
value: convertToDisplayAmount(
{ amount: lending.amount, denom: lending.denom },
new BNCoin({ amount: lending.amount, denom: lending.denom }),
displayCurrency,
prices,
).toString(),
@ -89,12 +92,8 @@ export const AccountBalancesTable = (props: Props) => {
accessorKey: 'value',
id: 'value',
cell: ({ row }) => {
return (
<DisplayCurrency
coin={{ denom: row.original.denom, amount: row.original.amount }}
className='text-right text-xs'
/>
)
const coin = new BNCoin({ denom: row.original.denom, amount: row.original.amount })
return <DisplayCurrency coin={coin} className='text-right text-xs' />
},
},
{

View File

@ -5,7 +5,9 @@ import DisplayCurrency from 'components/DisplayCurrency'
import { FormattedNumber } from 'components/FormattedNumber'
import { ArrowRight } from 'components/Icons'
import Text from 'components/Text'
import usePrices from 'hooks/usePrices'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import {
calculateAccountApr,
calculateAccountBorrowRate,
@ -30,7 +32,7 @@ interface ItemProps {
}
export default function AccountComposition(props: Props) {
const prices = useStore((s) => s.prices)
const { data: prices } = usePrices()
const balance = calculateAccountDeposits(props.account, prices)
const balanceChange = props.change ? calculateAccountDeposits(props.change, prices) : BN(0)
const debtBalance = calculateAccountDebt(props.account, prices)
@ -96,7 +98,7 @@ function Item(props: ItemProps) {
/>
) : (
<DisplayCurrency
coin={{ amount: props.current.toString(), denom: baseCurrency.denom }}
coin={new BNCoin({ amount: props.current.toString(), denom: baseCurrency.denom })}
className='text-sm'
/>
)}
@ -113,7 +115,7 @@ function Item(props: ItemProps) {
/>
) : (
<DisplayCurrency
coin={{ amount: props.change.toString(), denom: baseCurrency.denom }}
coin={new BNCoin({ amount: props.change.toString(), denom: baseCurrency.denom })}
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
/>
)}

View File

@ -3,6 +3,7 @@ import BigNumber from 'bignumber.js'
import AccountHealth from 'components/Account/AccountHealth'
import DisplayCurrency from 'components/DisplayCurrency'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
interface Props {
balance: BigNumber
@ -16,7 +17,7 @@ export default function AccountStats(props: Props) {
return (
<div className='w-full flex-wrap'>
<DisplayCurrency
coin={{ amount: props.balance.toString(), denom: baseCurrency.denom }}
coin={new BNCoin({ amount: props.balance.toString(), denom: baseCurrency.denom })}
className='w-full text-xl'
/>
<div className='mt-1 flex w-full items-center'>

View File

@ -7,7 +7,9 @@ import DisplayCurrency from 'components/DisplayCurrency'
import { ArrowChartLineUp } from 'components/Icons'
import Text from 'components/Text'
import useIsOpenArray from 'hooks/useIsOpenArray'
import usePrices from 'hooks/usePrices'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import { calculateAccountDeposits } from 'utils/accounts'
import { BN } from 'utils/helpers'
@ -18,8 +20,7 @@ interface Props {
export default function AccountSummary(props: Props) {
const [isOpen, toggleOpen] = useIsOpenArray(2, true)
const prices = useStore((s) => s.prices)
const { data: prices } = usePrices()
const baseCurrency = useStore((s) => s.baseCurrency)
const accountBalance = props.account ? calculateAccountDeposits(props.account, prices) : BN(0)
if (!props.account) return null
@ -29,7 +30,7 @@ export default function AccountSummary(props: Props) {
<Card className='mb-4 h-min min-w-fit bg-white/10' contentClassName='flex'>
<Item>
<DisplayCurrency
coin={{ amount: accountBalance.toString(), denom: baseCurrency.denom }}
coin={new BNCoin({ amount: accountBalance.toString(), denom: baseCurrency.denom })}
className='text-sm'
/>
</Item>

View File

@ -16,10 +16,6 @@ export default function AssetExpanded(props: AssetRowProps) {
const asset = marketAssets.find((asset) => asset.denom === props.row.original.denom)
let isActive: boolean = false
if ((props.row.original as BorrowAssetActive)?.debt) {
isActive = true
}
if (!asset) return null
function borrowHandler() {

View File

@ -1,4 +1,4 @@
import { Suspense } from 'react'
import { Suspense, useMemo } from 'react'
import { useParams } from 'react-router-dom'
import Card from 'components/Card'
@ -18,28 +18,28 @@ function Content(props: Props) {
const marketAssets = getEnabledMarketAssets()
function getBorrowAssets() {
return marketAssets.reduce(
(prev: { available: BorrowAsset[]; active: BorrowAssetActive[] }, curr) => {
const borrow = borrowData.find((borrow) => borrow.denom === curr.denom)
if (borrow) {
const debt = debtData?.find((debt) => debt.denom === curr.denom)
if (debt) {
prev.active.push({
...borrow,
debt: debt.amount,
})
} else {
prev.available.push(borrow)
const { available, active } = useMemo(
() =>
marketAssets.reduce(
(prev: { available: BorrowAsset[]; active: BorrowAssetActive[] }, curr) => {
const borrow = borrowData.find((borrow) => borrow.denom === curr.denom)
if (borrow) {
const debt = debtData?.find((debt) => debt.denom === curr.denom)
if (debt) {
prev.active.push({
...borrow,
debt: debt.amount,
})
} else {
prev.available.push(borrow)
}
}
}
return prev
},
{ available: [], active: [] },
)
}
const { available, active } = getBorrowAssets()
return prev
},
{ available: [], active: [] },
),
[marketAssets, borrowData, debtData],
)
const assets = props.type === 'active' ? active : available

View File

@ -43,9 +43,9 @@ export const buttonSizeClasses = {
}
export const buttonPaddingClasses = {
small: 'px-2.5 py-1.5 min-h-[32px]',
medium: 'px-3 py-2 min-h-[40px]',
large: 'px-3.5 py-2.5 min-h-[56px]',
small: 'px-4 py-1.5 min-h-[32px]',
medium: 'px-4 py-2 min-h-[40px]',
large: 'px-4 py-2.5 min-h-[56px]',
}
export const buttonVariantClasses = {

View File

@ -1,17 +1,18 @@
import { FormattedNumber } from 'components/FormattedNumber'
import usePrices from 'hooks/usePrices'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import { convertToDisplayAmount } from 'utils/formatters'
interface Props {
coin: BNCoin | Coin
coin: BNCoin
className?: string
isApproximation?: boolean
}
export default function DisplayCurrency(props: Props) {
const displayCurrency = useStore((s) => s.displayCurrency)
const prices = useStore((s) => s.prices)
const { data: prices } = usePrices()
return (
<FormattedNumber

View File

@ -1,38 +0,0 @@
import { Suspense } from 'react'
import Card from 'components/Card'
import { VaultTable } from 'components/Earn/vault/VaultTable'
import Text from 'components/Text'
import { IS_TESTNET } from 'constants/env'
import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults'
import useVaults from 'hooks/useVaults'
function Content() {
const { data: vaults } = useVaults()
if (!vaults.length) return null
return <VaultTable data={vaults} />
}
export default function AvailableVaults() {
return (
<Card title='Available vaults' className='mb-4 h-fit w-full bg-white/5'>
<Suspense fallback={<Fallback />}>
<Content />
</Suspense>
</Card>
)
}
function Fallback() {
// TODO: Replace with loading state of vaulttable
const vaults = IS_TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
return (
<>
{vaults.map((vault) => (
<Text key={vault.address}>{vault.name}</Text>
))}
</>
)
}

View File

@ -58,7 +58,7 @@ export default function VaultCard(props: Props) {
/>
<TitleAndSubCell
className='text-xs'
title={formatValue(props.vault.cap.used || '0', {
title={formatValue(props.vault.cap.used.integerValue().toNumber() || '0', {
abbreviated: true,
decimals: getAssetByDenom(props.vault.cap.denom)?.decimals,
})}
@ -66,7 +66,7 @@ export default function VaultCard(props: Props) {
/>
<TitleAndSubCell
className='text-xs'
title={formatValue(props.vault.cap.max || '0', {
title={formatValue(props.vault.cap.max.integerValue().toNumber() || '0', {
abbreviated: true,
decimals: getAssetByDenom(props.vault.cap.denom)?.decimals,
})}

View File

@ -1,11 +1,11 @@
import { Row } from '@tanstack/react-table'
import Button from 'components/Button'
import VaultCard from 'components/Earn/vault/VaultCard'
import Text from 'components/Text'
import { LockUnlocked, Plus } from 'components/Icons'
import useStore from 'store'
interface Props {
row: Row<Vault>
row: Row<Vault | DepositedVault>
resetExpanded: (defaultState?: boolean | undefined) => void
}
@ -19,6 +19,11 @@ export default function VaultExpanded(props: Props) {
})
}
let isDeposited: boolean = false
if ((props.row.original as DepositedVault)?.amounts) {
isDeposited = true
}
return (
<tr
key={props.row.id}
@ -30,27 +35,26 @@ export default function VaultExpanded(props: Props) {
!isExpanded && props.row.toggleExpanded()
}}
>
<td colSpan={5}>
<Text className='border-b border-white/10 px-4 py-5 '>Select bonding period</Text>
<div className='grid grid-cols-3 md:[&>div:nth-child(3)]:border-none'>
<VaultCard
vault={props.row.original}
title='1 day unbonding'
subtitle='$0 deposited'
unbondingPeriod={1}
/>
<VaultCard
vault={props.row.original}
title='7 day unbonding'
subtitle='$0 deposited'
unbondingPeriod={7}
/>
<VaultCard
vault={props.row.original}
title='14 day unbonding'
subtitle='$0 deposited'
unbondingPeriod={14}
/>
<td colSpan={isDeposited ? 6 : 5}>
<div className='align-center flex justify-end gap-3 p-4'>
{isDeposited ? (
<>
<Button color='secondary' leftIcon={<Plus className='w-3' />}>
Deposit more
</Button>
<Button color='tertiary' leftIcon={<LockUnlocked />}>
Unlock to withdraw
</Button>
</>
) : (
<Button
onClick={enterVaultHandler}
color='tertiary'
leftIcon={<Plus className='w-3' />}
>
Deposit
</Button>
)}
</div>
</td>
</tr>

View File

@ -1,10 +1,8 @@
import Image from 'next/image'
import AssetImage from 'components/AssetImage'
import { getAssetByDenom } from 'utils/assets'
interface Props {
vault: Vault
vault: VaultMetaData
}
export default function VaultLogo(props: Props) {
@ -19,7 +17,7 @@ export default function VaultLogo(props: Props) {
<AssetImage asset={primaryAsset} size={24} />
</div>
<div className='absolute'>
<AssetImage asset={primaryAsset} size={16} className='ml-5 mt-5' />
<AssetImage asset={secondaryAsset} size={16} className='ml-5 mt-5' />
</div>
</div>
)

View File

@ -3,6 +3,7 @@ import {
flexRender,
getCoreRowModel,
getSortedRowModel,
Row,
SortingState,
useReactTable,
} from '@tanstack/react-table'
@ -18,27 +19,58 @@ import TitleAndSubCell from 'components/TitleAndSubCell'
import { VAULT_DEPOSIT_BUFFER } from 'constants/vaults'
import { getAssetByDenom } from 'utils/assets'
import { convertPercentage, formatPercent, formatValue } from 'utils/formatters'
import DisplayCurrency from 'components/DisplayCurrency'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import Loading from 'components/Loading'
type Props = {
data: Vault[]
data: Vault[] | DepositedVault[]
isLoading?: boolean
}
export const VaultTable = (props: Props) => {
const [sorting, setSorting] = React.useState<SortingState>([])
const [sorting, setSorting] = React.useState<SortingState>([{ id: 'name', desc: true }])
const columns = React.useMemo<ColumnDef<Vault>[]>(
() => [
const baseCurrency = useStore((s) => s.baseCurrency)
const columns = React.useMemo<ColumnDef<Vault | DepositedVault>[]>(() => {
return [
{
header: 'Vault',
id: 'address',
accessorKey: 'name',
cell: ({ row }) => {
return <VaultLogo vault={row.original} />
return (
<div className='flex'>
<VaultLogo vault={row.original} />
<TitleAndSubCell
className='ml-2 mr-2 text-left'
title={`${row.original.name} - (${row.original.lockup.duration} ${row.original.lockup.timeframe})`}
sub={row.original.provider}
/>
</div>
)
},
},
...((props.data[0] as DepositedVault)?.values
? [
{
header: 'Pos. Value',
cell: ({ row }: { row: Row<DepositedVault | Vault> }) => {
const vault = row.original as DepositedVault
const positionValue = vault.values.primary.plus(vault.values.secondary)
const coin = BNCoin.fromDenomAndBigNumber(baseCurrency.denom, positionValue)
return <DisplayCurrency coin={coin} className='text-xs' />
},
},
]
: []),
{
accessorKey: 'apy',
header: 'APY',
cell: ({ row }) => {
if (row.original.apy === null) return <Loading />
return (
<Text size='xs'>{row.original.apy ? formatPercent(row.original.apy, 2) : '-'}</Text>
)
@ -48,29 +80,36 @@ export const VaultTable = (props: Props) => {
accessorKey: 'tvl',
header: 'TVL',
cell: ({ row }) => {
// TODO: Replace with DisplayCurrency
const symbol = getAssetByDenom(row.original.cap.denom)?.symbol ?? ''
return (
<Text size='xs'>
{formatValue(row.original.cap.used, { abbreviated: true, suffix: ` ${symbol}` })}
</Text>
)
if (props.isLoading) return <Loading />
const coin = new BNCoin({
denom: row.original.cap.denom,
amount: row.original.cap.used.toString(),
})
return <DisplayCurrency coin={coin} className='text-xs' />
},
},
{
accessorKey: 'cap',
header: 'Depo. Cap',
cell: ({ row }) => {
if (props.isLoading) return <Loading />
const percent = convertPercentage(
(row.original.cap.used / (row.original.cap.max * VAULT_DEPOSIT_BUFFER)) * 100,
row.original.cap.used
.div(row.original.cap.max.times(VAULT_DEPOSIT_BUFFER))
.times(100)
.integerValue()
.toNumber(),
)
const decimals = getAssetByDenom(row.original.cap.denom)?.decimals ?? 6
// TODO: Replace with DisplayCurrency
return (
<TitleAndSubCell
className='text-xs'
title={formatValue(row.original.cap.max, { abbreviated: true, decimals })}
title={formatValue(row.original.cap.max.integerValue().toNumber(), {
abbreviated: true,
decimals,
})}
sub={`${percent}% Filled`}
/>
)
@ -80,21 +119,24 @@ export const VaultTable = (props: Props) => {
accessorKey: 'details',
enableSorting: false,
header: 'Details',
cell: ({ row }) => (
<div className='flex items-center justify-end'>
<div className={classNames('w-4', row.getIsExpanded() && 'rotate-180')}>
<ChevronDown />
cell: ({ row }) => {
if (props.isLoading) return <Loading />
return (
<div className='flex items-center justify-end'>
<div className={classNames('w-4', row.getIsExpanded() && 'rotate-180')}>
<ChevronDown />
</div>
</div>
</div>
),
)
},
},
],
[],
)
]
}, [baseCurrency.denom, props.data, props.isLoading])
const table = useReactTable({
data: props.data,
columns,
columns: columns,
state: {
sorting,
},
@ -122,7 +164,7 @@ export const VaultTable = (props: Props) => {
<div
className={classNames(
'flex',
header.id === 'symbol' ? 'justify-start' : 'justify-end',
header.id === 'name' ? 'justify-start' : 'justify-end',
'align-center',
)}
>

View File

@ -0,0 +1,78 @@
import { Suspense, useMemo } from 'react'
import { useParams } from 'react-router-dom'
import Card from 'components/Card'
import { VaultTable } from 'components/Earn/vault/VaultTable'
import { IS_TESTNET } from 'constants/env'
import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults'
import useVaults from 'hooks/useVaults'
import useDepositedVaults from 'hooks/useDepositedVaults'
import { BN } from 'utils/helpers'
interface Props {
type: 'available' | 'deposited'
}
function Content(props: Props) {
const { accountId } = useParams()
const { data: vaults } = useVaults()
const { data: depositedVaults } = useDepositedVaults(accountId || '')
const vaultsMetaData = IS_TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
const { deposited, available } = useMemo(() => {
return vaultsMetaData.reduce(
(prev: { deposited: DepositedVault[]; available: Vault[] }, curr) => {
const vault = vaults.find((vault) => vault.address === curr.address)
const depositedVault = depositedVaults?.find((vault) => vault.address === curr.address)
if (depositedVault) {
prev.deposited.push(depositedVault)
} else if (vault) {
prev.available.push(vault)
}
return prev
},
{ deposited: [], available: [] },
)
}, [vaults, depositedVaults, vaultsMetaData])
const vaultsToDisplay = props.type === 'available' ? available : deposited
if (!vaultsToDisplay.length) return null
return <VaultTable data={vaultsToDisplay} />
}
export default function Vaults(props: Props) {
return (
<Card
title={props.type === 'available' ? 'Available vaults' : 'Deposited'}
className='mb-4 h-fit w-full bg-white/5'
>
<Suspense fallback={props.type === 'available' ? <Fallback /> : null}>
<Content type={props.type} />
</Suspense>
</Card>
)
}
function Fallback() {
const vaults = IS_TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
const mockVaults: Vault[] = vaults.map((vault) => ({
...vault,
apy: null,
ltv: {
max: 0,
liq: 0,
},
cap: {
denom: 'denom',
used: BN(0),
max: BN(0),
},
}))
return <VaultTable data={mockVaults} isLoading />
}

View File

@ -3,6 +3,7 @@ import TitleAndSubCell from 'components/TitleAndSubCell'
import { FormattedNumber } from 'components/FormattedNumber'
import useAssetIncentivesApy from 'hooks/useAssetIncentiveApy'
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
import { BNCoin } from 'types/classes/BNCoin'
interface Props {
data: LendingMarketTableData
@ -36,7 +37,11 @@ function DetailsHeader({ data }: Props) {
{accountLentAmount && (
<>
<TitleAndSubCell
title={<DisplayCurrency coin={{ denom: asset.denom, amount: accountLentAmount }} />}
title={
<DisplayCurrency
coin={new BNCoin({ denom: asset.denom, amount: accountLentAmount })}
/>
}
sub={'Deposited'}
/>
<div className='h-100 w-[1px] bg-white/10'></div>
@ -44,13 +49,18 @@ function DetailsHeader({ data }: Props) {
)}
{balanceInWallet && (
<>
<TitleAndSubCell title={<DisplayCurrency coin={balanceInWallet} />} sub={'In Wallet'} />
<TitleAndSubCell
title={<DisplayCurrency coin={new BNCoin(balanceInWallet)} />}
sub={'In Wallet'}
/>
<div className='h-100 w-[1px] bg-white/10'></div>
</>
)}
<TitleAndSubCell
title={
<DisplayCurrency coin={{ denom: asset.denom, amount: marketDepositCap.toString() }} />
<DisplayCurrency
coin={new BNCoin({ denom: asset.denom, amount: marketDepositCap.toString() })}
/>
}
sub={'Deposit Cap'}
/>

View File

@ -43,8 +43,8 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
const { actions: depositActions, fee: depositFee } = useDepositVault({
vault: props.vault,
deposits: props.deposits.filter((borrowing) => borrowing.amount.gt(0)),
borrowings: props.borrowings.filter((borrowing) => borrowing.amount.gt(0)),
deposits: props.deposits,
borrowings: props.borrowings,
})
const primaryValue = useMemo(
@ -189,7 +189,9 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
<div className='flex flex-col gap-2'>
<div className='flex justify-between'>
<Text className='text-white/50'>{`${props.primaryAsset.symbol}-${props.secondaryAsset.symbol} Position Value`}</Text>
<DisplayCurrency coin={{ denom: baseCurrency.denom, amount: totalValue.toString() }} />
<DisplayCurrency
coin={new BNCoin({ denom: baseCurrency.denom, amount: totalValue.toString() })}
/>
</div>
{props.borrowings.map((coin) => {
const asset = getAssetByDenom(coin.denom)

View File

@ -40,7 +40,7 @@ export default function VaultDepositSubTitle(props: Props) {
<>
{` = `}
<DisplayCurrency
coin={{ denom: baseCurrency.denom, amount: borrowingValue.toString() }}
coin={new BNCoin({ denom: baseCurrency.denom, amount: borrowingValue.toString() })}
/>
</>
)}

View File

@ -14,6 +14,7 @@ import { getAmount } from 'utils/accounts'
import { BN } from 'utils/helpers'
import { Gauge } from 'components/Gauge'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
interface Props {
primaryAmount: BigNumber
@ -204,7 +205,9 @@ export default function VaultDeposit(props: Props) {
</div>
<div className='flex justify-between'>
<Text className='text-white/50'>{`${props.primaryAsset.symbol}-${props.secondaryAsset.symbol} Deposit Value`}</Text>
<DisplayCurrency coin={{ denom: baseCurrency.denom, amount: totalValue.toString() }} />
<DisplayCurrency
coin={new BNCoin({ denom: baseCurrency.denom, amount: totalValue.toString() })}
/>
</div>
<Button
onClick={() => props.toggleOpen(1)}

View File

@ -3,6 +3,7 @@ import BigNumber from 'bignumber.js'
import DisplayCurrency from 'components/DisplayCurrency'
import usePrice from 'hooks/usePrice'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import { formatAmountWithSymbol } from 'utils/formatters'
interface Props {
@ -41,7 +42,9 @@ export default function VaultDepositSubTitle(props: Props) {
{(showPrimaryText || showSecondaryText) && (
<>
{` = `}
<DisplayCurrency coin={{ denom: baseCurrency.denom, amount: positionValue.toString() }} />
<DisplayCurrency
coin={new BNCoin({ denom: baseCurrency.denom, amount: positionValue.toString() })}
/>
</>
)}
</>

View File

@ -1,5 +1,4 @@
import classNames from 'classnames'
import Image from 'next/image'
import DisplayCurrency from 'components/DisplayCurrency'
import { ChevronDown } from 'components/Icons'
@ -7,6 +6,7 @@ import Text from 'components/Text'
import { ASSETS } from 'constants/assets'
import { formatValue } from 'utils/formatters'
import AssetImage from 'components/AssetImage'
import { BNCoin } from 'types/classes/BNCoin'
interface Props extends Option {
isSelected?: boolean
@ -68,7 +68,7 @@ export default function Option(props: Props) {
{formatValue(5, { maxDecimals: 2, minDecimals: 0, prefix: 'APY ', suffix: '%' })}
</Text>
<Text size='sm' className='col-span-2 text-right text-white/50'>
<DisplayCurrency coin={{ denom: asset.denom, amount: balance }} />
<DisplayCurrency coin={new BNCoin({ denom: asset.denom, amount: balance })} />
</Text>
</div>
)

View File

@ -12,10 +12,10 @@ interface Props {
export default function TitleAndSubCell(props: Props) {
return (
<div className={classNames('flex flex-col gap-[0.5]', props.containerClassName)}>
<Text size='sm' className={props.className}>
<Text size='xs' className={props.className}>
{props.title}
</Text>
<Text size='sm' className={classNames('text-white/50', props.className)}>
<Text size='xs' className={classNames('text-white/50', props.className)}>
{props.sub}
</Text>
</div>

View File

@ -72,7 +72,7 @@ export default function ConnectedButton() {
const assetDenoms = marketAssets.map((asset) => asset.denom)
const balances = walletBalances.filter((coin) => assetDenoms.includes(coin.denom))
useStore.setState({ balances })
}, [walletBalances, baseAsset.denom, baseAsset.decimals, marketAssets])
}, [walletBalances, baseAsset.denom, baseAsset.decimals, marketAssets, walletAmount])
return (
<div className={'relative'}>

View File

@ -27,7 +27,13 @@ export default function useDepositVault(props: Props): { actions: Action[]; fee:
const debouncedGetMinLpToReceive = useMemo(() => debounce(getMinLpToReceive, 500), [])
const { primaryCoin, secondaryCoin, totalValue } = useMemo(
() => getVaultDepositCoinsAndValue(props.vault, props.deposits, props.borrowings, prices),
() =>
getVaultDepositCoinsAndValue(
props.vault,
props.deposits.filter((borrowing) => borrowing.amount.gt(0)),
props.borrowings.filter((borrowing) => borrowing.amount.gt(0)),
prices,
),
[props.deposits, props.borrowings, props.vault, prices],
)
@ -41,8 +47,8 @@ export default function useDepositVault(props: Props): { actions: Action[]; fee:
() =>
getVaultSwapActions(
props.vault,
props.deposits,
props.borrowings,
props.deposits.filter((borrowing) => borrowing.amount.gt(0)),
props.borrowings.filter((borrowing) => borrowing.amount.gt(0)),
prices,
slippage,
totalValue,
@ -56,9 +62,10 @@ export default function useDepositVault(props: Props): { actions: Action[]; fee:
const lpAmount = await debouncedGetMinLpToReceive(
[secondaryCoin.toCoin(), primaryCoin.toCoin()],
props.vault.denoms.lp,
slippage,
)
if (!lpAmount || lpAmount === minLpToReceive) return
if (!lpAmount || lpAmount.eq(minLpToReceive)) return
setMinLpToReceive(lpAmount)
}, [
primaryCoin,
@ -66,6 +73,7 @@ export default function useDepositVault(props: Props): { actions: Action[]; fee:
props.vault.denoms.lp,
debouncedGetMinLpToReceive,
minLpToReceive,
slippage,
])
const enterVaultActions: Action[] = useMemo(() => {

View File

@ -1,14 +0,0 @@
import useSWR from 'swr'
import getMinLpToReceive from 'api/vaults/getMinLpToReceive'
import { BN } from 'utils/helpers'
export default function useMinLpToReceive(coins: Coin[], lpDenom: string) {
return useSWR(
`minLpToReceive-${JSON.stringify(coins)}`,
() => getMinLpToReceive(coins, lpDenom),
{
fallbackData: BN(0),
},
)
}

View File

@ -1,12 +1,10 @@
import useSWR from 'swr'
import getPrices from 'api/prices/getPrices'
import useStore from 'store'
export default function usePrices() {
return useSWR('prices', getPrices, {
fallbackData: [],
refreshInterval: 30000,
onSuccess: (prices) => useStore.setState({ prices }),
})
}

View File

@ -1,13 +1,13 @@
import AvailableVaults from 'components/Earn/vault/AvailableVaults'
import FeaturedVaults from 'components/Earn/vault/FeaturedVaults'
import Tab from 'components/Earn/Tab'
import Vaults from 'components/Earn/vault/Vaults'
export default function FarmPage() {
return (
<>
<Tab isFarm />
<FeaturedVaults />
<AvailableVaults />
{/* <FeaturedVaults /> */}
<Vaults type='deposited' />
<Vaults type='available' />
</>
)
}

View File

@ -136,20 +136,8 @@ export default function createBroadcastSlice(
},
}
const response = await get().executeMsg({ msg, fee: options.fee })
if (response.result) {
set({
toast: {
message: `Deposited into vault`,
},
})
} else {
set({
toast: {
message: response.error ?? `Transaction failed: ${response.error}`,
isError: true,
},
})
}
handleResponseMessages(response, `Deposited into vault`)
return !!response.result
},
withdraw: async (options: { fee: StdFee; accountId: string; coin: Coin }) => {

View File

@ -9,6 +9,5 @@ export default function createCurrencySlice(
return {
baseCurrency: ASSETS[0],
displayCurrency: ASSETS.find((asset) => asset.denom === ASSETS[0].denom)!,
prices: [],
}
}

View File

@ -1,5 +1,4 @@
interface CurrencySlice {
baseCurrency: Asset
displayCurrency: Asset
prices: Coin[]
}

View File

@ -27,8 +27,8 @@ interface VaultInfo {
}
cap: {
denom: string
used: number
max: number
used: BigNumber
max: BigNumber
}
}

View File

@ -7,7 +7,7 @@ export const hardcodedFee = {
amount: '100000',
},
],
gas: '5000000',
gas: '10000000',
}
export const SECONDS_IN_A_YEAR = 31540000

View File

@ -156,11 +156,7 @@ export function demagnify(amount: number | string | BigNumber, asset: Asset) {
return value.isZero() ? 0 : value.shiftedBy(-1 * asset.decimals).toNumber()
}
export function convertToDisplayAmount(
coin: BNCoin | Coin,
displayCurrency: Asset,
prices: Coin[],
) {
export function convertToDisplayAmount(coin: BNCoin, displayCurrency: Asset, prices: Coin[]) {
const price = prices.find((price) => price.denom === coin.denom)
const asset = getEnabledMarketAssets().find((asset) => asset.denom === coin.denom)
const displayPrice = prices.find((price) => price.denom === displayCurrency.denom)

View File

@ -1,3 +1,4 @@
import { BNCoin } from 'types/classes/BNCoin'
import { Positions as CreditManagerPosition } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
import { Market as RedBankMarket } from 'types/generated/mars-mock-red-bank/MarsMockRedBank.types'
@ -8,9 +9,9 @@ export function resolvePositionResponses(responses: CreditManagerPosition[]): Ac
export function resolvePositionResponse(response: CreditManagerPosition): Account {
return {
id: response.account_id,
deposits: response.deposits,
debts: response.debts,
lends: response.lends,
debts: response.debts.map((debt) => new BNCoin(debt)),
lends: response.lends.map((lend) => new BNCoin(lend)),
deposits: response.deposits.map((deposit) => new BNCoin(deposit)),
vaults: response.vaults,
}
}

View File

@ -49,14 +49,14 @@ export function getVaultDepositCoinsAndValue(
return prev.plus(bnCoin.amount.times(price))
}, BN(0))
const primaryDepositAmount = getTokenPrice(vault.denoms.primary, prices)
.times(totalValue)
.div(2)
const halfValue = totalValue.div(2)
const primaryDepositAmount = halfValue
.div(getTokenPrice(vault.denoms.primary, prices))
.integerValue()
const secondaryDepositAmount = getTokenPrice(vault.denoms.secondary, prices)
.times(totalValue)
.div(2)
const secondaryDepositAmount = halfValue
.div(getTokenPrice(vault.denoms.secondary, prices))
.integerValue()
return {