Mp 2949 implemet health computer for borrow (#311)
* implemented max borrow for borrow page setup basic useHealthComputer * finish up healthcomputer * updated tests
This commit is contained in:
parent
2d13601365
commit
3413203ca7
@ -1,26 +1,23 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import * as rrd from 'react-router-dom'
|
||||
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import AccountDetails from 'components/Account/AccountDetails'
|
||||
|
||||
jest.mock('react-router-dom')
|
||||
const mockedUseParams = rrd.useParams as jest.Mock
|
||||
jest.mock('hooks/useCurrentAccount', () => jest.fn(() => null))
|
||||
|
||||
const mockedUseCurrentAccount = useCurrentAccount as jest.Mock
|
||||
|
||||
describe('<AccountDetails />', () => {
|
||||
afterAll(() => {
|
||||
mockedUseParams.mockRestore()
|
||||
})
|
||||
|
||||
it('renders account details WHEN accountId specified in the params', () => {
|
||||
mockedUseParams.mockReturnValue({ accountId: 1 })
|
||||
it('renders account details WHEN account is selected', () => {
|
||||
mockedUseCurrentAccount.mockReturnValue({ id: 1 })
|
||||
render(<AccountDetails />)
|
||||
|
||||
const container = screen.queryByTestId('account-details')
|
||||
expect(container).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not render WHEN accountId is NOT specified in the params', () => {
|
||||
mockedUseParams.mockReturnValue({ accountId: null })
|
||||
it('does not render WHEN account is NOT selected', () => {
|
||||
mockedUseCurrentAccount.mockReturnValue(null)
|
||||
render(<AccountDetails />)
|
||||
|
||||
const container = screen.queryByTestId('account-details')
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import LendingDetails from 'components/MarketAssetTable/MarketDetails'
|
||||
import MarketDetails from 'components/MarketAssetTable/MarketDetails'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
@ -31,7 +31,7 @@ describe('<LendingDetails />', () => {
|
||||
})
|
||||
|
||||
it('should render', () => {
|
||||
const { container } = render(<LendingDetails data={data} />)
|
||||
const { container } = render(<MarketDetails type='lend' data={data} />)
|
||||
expect(container).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
@ -7,6 +7,7 @@ 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'
|
||||
import { hardcodedFee } from 'utils/constants'
|
||||
|
||||
jest.mock('hooks/usePrices', () =>
|
||||
jest.fn(() => ({
|
||||
@ -47,9 +48,7 @@ describe('<VaultBorrowings />', () => {
|
||||
const defaultProps: VaultBorrowingsProps = {
|
||||
primaryAsset: ASSETS[0],
|
||||
secondaryAsset: ASSETS[1],
|
||||
primaryAmount: BN(0),
|
||||
secondaryAmount: BN(0),
|
||||
account: {
|
||||
updatedAccount: {
|
||||
id: 'test',
|
||||
deposits: [],
|
||||
debts: [],
|
||||
@ -60,6 +59,8 @@ describe('<VaultBorrowings />', () => {
|
||||
borrowings: [],
|
||||
deposits: [],
|
||||
onChangeBorrowings: jest.fn(),
|
||||
depositActions: [],
|
||||
depositFee: hardcodedFee,
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
|
@ -10,6 +10,11 @@ module.exports = {
|
||||
'!<rootDir>/*.config.js',
|
||||
'!<rootDir>/coverage/**',
|
||||
'!<rootDir>/src/types/**',
|
||||
'!<rootDir>/src/utils/charting_library/**',
|
||||
'!<rootDir>/src/utils/datafeeds/**',
|
||||
'!<rootDir>/public/charting_library/**',
|
||||
'!<rootDir>/public/datafeeds/**',
|
||||
'!<rootDir>/src/utils/health_computer/**',
|
||||
],
|
||||
moduleNameMapper: {
|
||||
// Handle CSS imports (with CSS modules)
|
||||
|
@ -1,15 +1,23 @@
|
||||
import { getCreditManagerQueryClient } from 'api/cosmwasm-client'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import getDepositedVaults from 'api/vaults/getDepositedVaults'
|
||||
import { Positions } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import { resolvePositionResponse } from 'utils/resolvers'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
|
||||
export default async function getAccount(accountId: string): Promise<Account> {
|
||||
const creditManagerQueryClient = await getCreditManagerQueryClient()
|
||||
|
||||
const accountPosition: Positions = await creditManagerQueryClient.positions({ accountId })
|
||||
|
||||
const depositedVaults = await getDepositedVaults(accountId)
|
||||
|
||||
if (accountPosition) {
|
||||
return resolvePositionResponse(accountPosition)
|
||||
return {
|
||||
id: accountPosition.account_id,
|
||||
debts: accountPosition.debts.map((debt) => new BNCoin(debt)),
|
||||
lends: accountPosition.lends.map((lend) => new BNCoin(lend)),
|
||||
deposits: accountPosition.deposits.map((deposit) => new BNCoin(deposit)),
|
||||
vaults: depositedVaults,
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise((_, reject) => reject('No account found'))
|
||||
|
@ -1,12 +0,0 @@
|
||||
import getAccount from 'api/accounts/getAccount'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
|
||||
export default async function getAccountDebts(accountId: string): Promise<BNCoin[]> {
|
||||
const account = await getAccount(accountId)
|
||||
|
||||
if (account) {
|
||||
return account.debts
|
||||
}
|
||||
|
||||
return new Promise((_, reject) => reject('Account not found'))
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import getAccount from 'api/accounts/getAccount'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
|
||||
export default async function getAccountDeposits(accountId: string): Promise<BNCoin[]> {
|
||||
const account = await getAccount(accountId)
|
||||
|
||||
if (account) {
|
||||
return account.deposits
|
||||
}
|
||||
|
||||
return new Promise((_, reject) => reject('Account not found'))
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import getAccount from 'api/accounts/getAccount'
|
||||
|
||||
export default async function getAccountDeposits(accountId: string) {
|
||||
const account = await getAccount(accountId)
|
||||
|
||||
if (account) {
|
||||
return account.vaults
|
||||
}
|
||||
|
||||
return new Promise((_, reject) => reject('Account not found'))
|
||||
}
|
12
src/api/params/getAssetParams.ts
Normal file
12
src/api/params/getAssetParams.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { getParamsQueryClient } from 'api/cosmwasm-client'
|
||||
import { AssetParamsBaseForAddr } from 'types/generated/mars-params/MarsParams.types'
|
||||
|
||||
export default async function getAssetParams(): Promise<AssetParamsBaseForAddr[]> {
|
||||
try {
|
||||
const paramsQueryClient = await getParamsQueryClient()
|
||||
|
||||
return paramsQueryClient.allAssetParams({})
|
||||
} catch (ex) {
|
||||
throw ex
|
||||
}
|
||||
}
|
@ -117,7 +117,7 @@ async function getVaultValuesAndAmounts(
|
||||
const lpTokensQuery = getLpTokensForVaultPosition(vault, vaultPosition)
|
||||
const amounts = flatVaultPositionAmount(vaultPosition.amount)
|
||||
|
||||
const [[primaryLpToken, secondaryLpToken], [primaryAsset, secondaryAsset]] = await Promise.all([
|
||||
const [[primaryLpToken, secondaryLpToken], [primaryPrice, secondaryPrice]] = await Promise.all([
|
||||
lpTokensQuery,
|
||||
pricesQueries,
|
||||
])
|
||||
@ -129,8 +129,8 @@ async function getVaultValuesAndAmounts(
|
||||
secondary: BN(secondaryLpToken.amount),
|
||||
},
|
||||
values: {
|
||||
primary: BN(primaryLpToken.amount).multipliedBy(primaryAsset),
|
||||
secondary: BN(secondaryLpToken.amount).multipliedBy(secondaryAsset),
|
||||
primary: BN(primaryLpToken.amount).multipliedBy(primaryPrice),
|
||||
secondary: BN(secondaryLpToken.amount).multipliedBy(secondaryPrice),
|
||||
},
|
||||
}
|
||||
} catch (ex) {
|
||||
|
14
src/api/vaults/getVaultTokenFromLp.ts
Normal file
14
src/api/vaults/getVaultTokenFromLp.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { getVaultQueryClient } from 'api/cosmwasm-client'
|
||||
|
||||
export async function getVaultTokenFromLp(
|
||||
vaultAddress: string,
|
||||
lpAmount: string,
|
||||
): Promise<{ vaultAddress: string; amount: string }> {
|
||||
try {
|
||||
const client = await getVaultQueryClient(vaultAddress)
|
||||
|
||||
return client.previewDeposit({ amount: lpAmount }).then((amount) => ({ vaultAddress, amount }))
|
||||
} catch (ex) {
|
||||
throw ex
|
||||
}
|
||||
}
|
@ -1,17 +1,15 @@
|
||||
import { resolvePositionResponses } from 'utils/resolvers'
|
||||
import getWalletAccountIds from 'api/wallets/getAccountIds'
|
||||
import { getCreditManagerQueryClient } from 'api/cosmwasm-client'
|
||||
import getAccount from 'api/accounts/getAccount'
|
||||
|
||||
export default async function getAccounts(address: string): Promise<Account[]> {
|
||||
const accountIds: string[] = await getWalletAccountIds(address)
|
||||
const creditManagerQueryClient = await getCreditManagerQueryClient()
|
||||
|
||||
const $accounts = accountIds.map((accountId) => creditManagerQueryClient.positions({ accountId }))
|
||||
const $accounts = accountIds.map((accountId) => getAccount(accountId))
|
||||
|
||||
const accounts = await Promise.all($accounts).then((accounts) => accounts)
|
||||
|
||||
if (accounts) {
|
||||
return resolvePositionResponses(accounts)
|
||||
return accounts
|
||||
}
|
||||
|
||||
return new Promise((_, reject) => reject('No data'))
|
||||
|
@ -1,15 +1,22 @@
|
||||
import { useParams } from 'react-router-dom'
|
||||
|
||||
import { Gauge } from 'components/Gauge'
|
||||
import { Heart } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import { isNumber } from 'utils/parsers'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
|
||||
export default function AccountDetails() {
|
||||
const { accountId } = useParams()
|
||||
const hasAccount = isNumber(accountId)
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
return hasAccount ? (
|
||||
export default function AccountDetailsController() {
|
||||
const account = useCurrentAccount()
|
||||
|
||||
if (!account) return null
|
||||
|
||||
return <AccountDetails account={account} />
|
||||
}
|
||||
|
||||
function AccountDetails(props: Props) {
|
||||
return (
|
||||
<div
|
||||
data-testid='account-details'
|
||||
className='w-16 rounded-base border border-white/20 bg-white/5 backdrop-blur-sticky'
|
||||
@ -40,5 +47,5 @@ export default function AccountDetails() {
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
) : null
|
||||
)
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
import getAccountDebts from 'api/accounts/getAccountDebts'
|
||||
|
||||
interface Props {
|
||||
accountId: string
|
||||
}
|
||||
|
||||
export async function AccountDebtTable(props: Props) {
|
||||
const debtData = await getAccountDebts(props.accountId)
|
||||
|
||||
return debtData.map((debt) => {
|
||||
return (
|
||||
<p key={debt.denom}>
|
||||
{debt.denom} {debt.amount.toString()}
|
||||
</p>
|
||||
)
|
||||
})
|
||||
}
|
@ -19,6 +19,7 @@ import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { hardcodedFee } from 'utils/constants'
|
||||
import { formatPercent, formatValue } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
|
||||
function getDebtAmount(modal: BorrowModal | null) {
|
||||
return BN((modal?.marketData as BorrowMarketTableData)?.debt ?? 0).toString()
|
||||
@ -29,8 +30,18 @@ function getAssetLogo(modal: BorrowModal | null) {
|
||||
return <AssetImage asset={modal.asset} size={24} />
|
||||
}
|
||||
|
||||
export default function BorrowModal() {
|
||||
const currentAccount = useCurrentAccount()
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
export default function BorrowModalController() {
|
||||
const account = useCurrentAccount()
|
||||
if (!account) return null
|
||||
|
||||
return <BorrowModal account={account} />
|
||||
}
|
||||
|
||||
function BorrowModal(props: Props) {
|
||||
const [percentage, setPercentage] = useState(0)
|
||||
const [amount, setAmount] = useState(BN(0))
|
||||
const [change, setChange] = useState<AccountChange | undefined>()
|
||||
@ -41,6 +52,9 @@ export default function BorrowModal() {
|
||||
const repay = useStore((s) => s.repay)
|
||||
const asset = modal?.asset ?? ASSETS[0]
|
||||
const isRepay = modal?.isRepay ?? false
|
||||
const [max, setMax] = useState(BN(0))
|
||||
|
||||
const { computeMaxBorrowAmount } = useHealthComputer(props.account)
|
||||
|
||||
function resetState() {
|
||||
setAmount(BN(0))
|
||||
@ -49,20 +63,20 @@ export default function BorrowModal() {
|
||||
}
|
||||
|
||||
async function onConfirmClick() {
|
||||
if (!modal?.asset || !currentAccount) return
|
||||
if (!modal?.asset) return
|
||||
setIsConfirming(true)
|
||||
let result
|
||||
if (isRepay) {
|
||||
result = await repay({
|
||||
fee: hardcodedFee,
|
||||
accountId: currentAccount.id,
|
||||
accountId: props.account.id,
|
||||
coin: BNCoin.fromDenomAndBigNumber(modal.asset.denom, amount),
|
||||
accountBalance: percentage === 100,
|
||||
})
|
||||
} else {
|
||||
result = await borrow({
|
||||
fee: hardcodedFee,
|
||||
accountId: currentAccount.id,
|
||||
accountId: props.account.id,
|
||||
coin: { denom: modal.asset.denom, amount: amount.toString() },
|
||||
borrowToWallet,
|
||||
})
|
||||
@ -90,7 +104,16 @@ export default function BorrowModal() {
|
||||
decimals: 6,
|
||||
})
|
||||
|
||||
const max = BN(isRepay ? getDebtAmount(modal) : modal?.marketData?.liquidity?.amount ?? '0')
|
||||
useEffect(() => {
|
||||
if (isRepay) {
|
||||
setMax(BN(getDebtAmount(modal)))
|
||||
return
|
||||
}
|
||||
|
||||
computeMaxBorrowAmount(asset.denom).then((maxBorrowAmount) => {
|
||||
setMax(BN(Math.min(maxBorrowAmount, modal?.marketData?.liquidity?.amount.toNumber() || 0)))
|
||||
})
|
||||
}, [isRepay, modal, asset.denom, computeMaxBorrowAmount])
|
||||
|
||||
useEffect(() => {
|
||||
if (!modal?.asset) return
|
||||
@ -109,7 +132,7 @@ export default function BorrowModal() {
|
||||
},
|
||||
],
|
||||
})
|
||||
}, [amount, modal?.asset, currentAccount, isRepay])
|
||||
}, [amount, modal?.asset, props.account, isRepay])
|
||||
|
||||
if (!modal) return null
|
||||
return (
|
||||
@ -183,7 +206,7 @@ export default function BorrowModal() {
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummary account={currentAccount} change={change} />
|
||||
<AccountSummary account={props.account} change={change} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
|
@ -8,53 +8,35 @@ import { ArrowRight, ExclamationMarkCircled } from 'components/Icons'
|
||||
import Slider from 'components/Slider'
|
||||
import Text from 'components/Text'
|
||||
import TokenInput from 'components/TokenInput'
|
||||
import useDepositVault from 'hooks/broadcast/useDepositVault'
|
||||
import useMarketAssets from 'hooks/useMarketAssets'
|
||||
import usePrice from 'hooks/usePrice'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { findCoinByDenom, getAssetByDenom } from 'utils/assets'
|
||||
import { formatPercent } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { calculateMaxBorrowAmounts } from 'utils/vaults'
|
||||
import { Action } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
|
||||
export interface VaultBorrowingsProps {
|
||||
account: Account
|
||||
updatedAccount: Account
|
||||
borrowings: BNCoin[]
|
||||
primaryAmount: BigNumber
|
||||
secondaryAmount: BigNumber
|
||||
deposits: BNCoin[]
|
||||
primaryAsset: Asset
|
||||
secondaryAsset: Asset
|
||||
deposits: BNCoin[]
|
||||
vault: Vault
|
||||
depositActions: Action[]
|
||||
depositFee: StdFee
|
||||
onChangeBorrowings: (borrowings: BNCoin[]) => void
|
||||
}
|
||||
|
||||
export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
const { data: marketAssets } = useMarketAssets()
|
||||
const { data: prices } = usePrices()
|
||||
const primaryPrice = usePrice(props.primaryAsset.denom)
|
||||
const secondaryPrice = usePrice(props.secondaryAsset.denom)
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
const vaultModal = useStore((s) => s.vaultModal)
|
||||
const depositIntoVault = useStore((s) => s.depositIntoVault)
|
||||
const [isConfirming, setIsConfirming] = useState(false)
|
||||
|
||||
const { actions: depositActions, fee: depositFee } = useDepositVault({
|
||||
vault: props.vault,
|
||||
deposits: props.deposits,
|
||||
borrowings: props.borrowings,
|
||||
})
|
||||
|
||||
const primaryValue = useMemo(
|
||||
() => props.primaryAmount.multipliedBy(primaryPrice),
|
||||
[props.primaryAmount, primaryPrice],
|
||||
)
|
||||
const secondaryValue = useMemo(
|
||||
() => props.secondaryAmount.multipliedBy(secondaryPrice),
|
||||
[props.secondaryAmount, secondaryPrice],
|
||||
)
|
||||
const maxBorrowAmounts: BNCoin[] = []
|
||||
|
||||
const borrowingValue = useMemo(() => {
|
||||
return props.borrowings.reduce((prev, curr) => {
|
||||
@ -65,10 +47,16 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
}, BN(0) as BigNumber)
|
||||
}, [props.borrowings, prices])
|
||||
|
||||
const totalValue = useMemo(
|
||||
() => primaryValue.plus(secondaryValue).plus(borrowingValue),
|
||||
[primaryValue, secondaryValue, borrowingValue],
|
||||
)
|
||||
const totalValue = useMemo(() => {
|
||||
const depositValue = props.deposits.reduce((prev, curr) => {
|
||||
const price = prices.find((price) => price.denom === curr.denom)?.amount
|
||||
if (!price) return prev
|
||||
const value = curr.amount.multipliedBy(price)
|
||||
return prev.plus(value)
|
||||
}, BN(0) as BigNumber)
|
||||
|
||||
return depositValue.plus(borrowingValue)
|
||||
}, [props.deposits, borrowingValue, prices])
|
||||
|
||||
useEffect(() => {
|
||||
const selectedBorrowDenoms = vaultModal?.selectedBorrowDenoms || []
|
||||
@ -89,17 +77,6 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
props.onChangeBorrowings(updatedBorrowings)
|
||||
}, [vaultModal, props])
|
||||
|
||||
const maxAmounts: BNCoin[] = useMemo(
|
||||
() =>
|
||||
calculateMaxBorrowAmounts(
|
||||
props.account,
|
||||
marketAssets,
|
||||
prices,
|
||||
props.borrowings.map((coin) => coin.denom),
|
||||
),
|
||||
[props.borrowings, marketAssets, prices, props.account],
|
||||
)
|
||||
|
||||
const [percentage, setPercentage] = useState<number>(0)
|
||||
|
||||
function onChangeSlider(value: number) {
|
||||
@ -107,7 +84,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
|
||||
const denom = props.borrowings[0].denom
|
||||
const currentAmount = props.borrowings[0].amount
|
||||
const maxAmount = maxAmounts.find((coin) => coin.denom === denom)?.amount ?? BN(0)
|
||||
const maxAmount = maxBorrowAmounts.find((coin) => coin.denom === denom)?.amount ?? BN(0)
|
||||
const newBorrowings: BNCoin[] = [
|
||||
new BNCoin({
|
||||
denom,
|
||||
@ -152,9 +129,9 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
async function onConfirm() {
|
||||
setIsConfirming(true)
|
||||
const isSuccess = await depositIntoVault({
|
||||
fee: depositFee,
|
||||
accountId: props.account.id,
|
||||
actions: depositActions,
|
||||
fee: props.depositFee,
|
||||
accountId: props.updatedAccount.id,
|
||||
actions: props.depositActions,
|
||||
})
|
||||
setIsConfirming(false)
|
||||
if (isSuccess) {
|
||||
@ -166,7 +143,9 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
<div className='flex flex-1 flex-col gap-4 p-4'>
|
||||
{props.borrowings.map((coin) => {
|
||||
const asset = getAssetByDenom(coin.denom)
|
||||
const maxAmount = maxAmounts.find((maxAmount) => maxAmount.denom === coin.denom)?.amount
|
||||
const maxAmount = maxBorrowAmounts.find(
|
||||
(maxAmount) => maxAmount.denom === coin.denom,
|
||||
)?.amount
|
||||
if (!asset || !maxAmount)
|
||||
return <React.Fragment key={`input-${coin.denom}`}></React.Fragment>
|
||||
return (
|
||||
@ -222,7 +201,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
text='Deposit'
|
||||
rightIcon={<ArrowRight />}
|
||||
showProgressIndicator={isConfirming}
|
||||
disabled={!depositActions.length}
|
||||
disabled={!props.depositActions.length}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
@ -15,35 +15,44 @@ import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { getAmount } from 'utils/accounts'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { findCoinByDenom } from 'utils/assets'
|
||||
|
||||
interface Props {
|
||||
primaryAmount: BigNumber
|
||||
secondaryAmount: BigNumber
|
||||
deposits: BNCoin[]
|
||||
primaryAsset: Asset
|
||||
secondaryAsset: Asset
|
||||
account: Account
|
||||
isCustomRatio: boolean
|
||||
onChangeDeposits: (deposits: BNCoin[]) => void
|
||||
onChangeIsCustomRatio: (isCustomRatio: boolean) => void
|
||||
onChangePrimaryAmount: (amount: BigNumber) => void
|
||||
onChangeSecondaryAmount: (amount: BigNumber) => void
|
||||
toggleOpen: (index: number) => void
|
||||
}
|
||||
|
||||
export default function VaultDeposit(props: Props) {
|
||||
const { deposits, primaryAsset, secondaryAsset, account, onChangeDeposits } = props
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
const availablePrimaryAmount = getAmount(primaryAsset.denom, account.deposits)
|
||||
const availableSecondaryAmount = getAmount(secondaryAsset.denom, account.deposits)
|
||||
const primaryPrice = usePrice(primaryAsset.denom)
|
||||
const secondaryPrice = usePrice(secondaryAsset.denom)
|
||||
|
||||
const availablePrimaryAmount = getAmount(props.primaryAsset.denom, props.account.deposits)
|
||||
const availableSecondaryAmount = getAmount(props.secondaryAsset.denom, props.account.deposits)
|
||||
const primaryPrice = usePrice(props.primaryAsset.denom)
|
||||
const secondaryPrice = usePrice(props.secondaryAsset.denom)
|
||||
const primaryCoin = useMemo(() => {
|
||||
const amount = findCoinByDenom(primaryAsset.denom, deposits)?.amount.toString() || '0'
|
||||
return new BNCoin({ denom: primaryAsset.denom, amount })
|
||||
}, [deposits, primaryAsset.denom])
|
||||
|
||||
const secondaryCoin = useMemo(() => {
|
||||
const amount = findCoinByDenom(secondaryAsset.denom, deposits)?.amount.toString() || '0'
|
||||
return new BNCoin({ denom: secondaryAsset.denom, amount })
|
||||
}, [deposits, secondaryAsset.denom])
|
||||
|
||||
const primaryValue = useMemo(
|
||||
() => props.primaryAmount.multipliedBy(primaryPrice),
|
||||
[props.primaryAmount, primaryPrice],
|
||||
() => primaryCoin.amount.multipliedBy(primaryPrice),
|
||||
[primaryCoin, primaryPrice],
|
||||
)
|
||||
const secondaryValue = useMemo(
|
||||
() => props.secondaryAmount.multipliedBy(secondaryPrice),
|
||||
[props.secondaryAmount, secondaryPrice],
|
||||
() => secondaryCoin.amount.multipliedBy(secondaryPrice),
|
||||
[secondaryCoin, secondaryPrice],
|
||||
)
|
||||
const totalValue = useMemo(
|
||||
() => primaryValue.plus(secondaryValue),
|
||||
@ -71,7 +80,9 @@ export default function VaultDeposit(props: Props) {
|
||||
)
|
||||
const primaryMax = useMemo(
|
||||
() =>
|
||||
props.isCustomRatio ? availablePrimaryAmount : maxAssetValueNonCustom.dividedBy(primaryPrice),
|
||||
props.isCustomRatio
|
||||
? availablePrimaryAmount
|
||||
: maxAssetValueNonCustom.dividedBy(primaryPrice).integerValue(),
|
||||
[props.isCustomRatio, availablePrimaryAmount, primaryPrice, maxAssetValueNonCustom],
|
||||
)
|
||||
const secondaryMax = useMemo(
|
||||
@ -92,8 +103,9 @@ export default function VaultDeposit(props: Props) {
|
||||
function handleSwitch() {
|
||||
const isCustomRatioNew = !props.isCustomRatio
|
||||
if (!isCustomRatioNew) {
|
||||
props.onChangePrimaryAmount(BN(0))
|
||||
props.onChangeSecondaryAmount(BN(0))
|
||||
primaryCoin.amount = BN(0)
|
||||
secondaryCoin.amount = BN(0)
|
||||
onChangeDeposits([primaryCoin, secondaryCoin])
|
||||
setPercentage(0)
|
||||
}
|
||||
props.onChangeIsCustomRatio(isCustomRatioNew)
|
||||
@ -103,28 +115,33 @@ export default function VaultDeposit(props: Props) {
|
||||
if (amount.isGreaterThan(primaryMax)) {
|
||||
amount = primaryMax
|
||||
}
|
||||
props.onChangePrimaryAmount(amount)
|
||||
primaryCoin.amount = amount
|
||||
setPercentage(amount.dividedBy(primaryMax).multipliedBy(100).decimalPlaces(0).toNumber())
|
||||
if (!props.isCustomRatio) {
|
||||
props.onChangeSecondaryAmount(secondaryMax.multipliedBy(amount.dividedBy(primaryMax)))
|
||||
secondaryCoin.amount = secondaryMax.multipliedBy(amount.dividedBy(primaryMax)).integerValue()
|
||||
}
|
||||
|
||||
onChangeDeposits([primaryCoin, secondaryCoin])
|
||||
}
|
||||
|
||||
function onChangeSecondaryDeposit(amount: BigNumber) {
|
||||
if (amount.isGreaterThan(secondaryMax)) {
|
||||
amount = secondaryMax
|
||||
}
|
||||
props.onChangeSecondaryAmount(amount)
|
||||
secondaryCoin.amount = amount
|
||||
setPercentage(amount.dividedBy(secondaryMax).multipliedBy(100).decimalPlaces(0).toNumber())
|
||||
if (!props.isCustomRatio) {
|
||||
props.onChangePrimaryAmount(primaryMax.multipliedBy(amount.dividedBy(secondaryMax)))
|
||||
primaryCoin.amount = primaryMax.multipliedBy(amount.dividedBy(secondaryMax)).integerValue()
|
||||
}
|
||||
|
||||
onChangeDeposits([primaryCoin, secondaryCoin])
|
||||
}
|
||||
|
||||
function onChangeSlider(value: number) {
|
||||
setPercentage(value)
|
||||
props.onChangePrimaryAmount(primaryMax.multipliedBy(value / 100))
|
||||
props.onChangeSecondaryAmount(secondaryMax.multipliedBy(value / 100))
|
||||
primaryCoin.amount = primaryMax.multipliedBy(value / 100).integerValue()
|
||||
secondaryCoin.amount = secondaryMax.multipliedBy(value / 100).integerValue()
|
||||
onChangeDeposits([primaryCoin, secondaryCoin])
|
||||
}
|
||||
|
||||
function getWarningText(asset: Asset) {
|
||||
@ -137,7 +154,7 @@ export default function VaultDeposit(props: Props) {
|
||||
<div className='flex flex-col items-center justify-between gap-1 pb-[30px] pt-2'>
|
||||
<Gauge
|
||||
percentage={primaryValuePercentage}
|
||||
tooltip={`${primaryValuePercentage}% of value is ${props.primaryAsset.symbol}`}
|
||||
tooltip={`${primaryValuePercentage}% of value is ${primaryAsset.symbol}`}
|
||||
labelClassName='text-martian-red'
|
||||
diameter={32}
|
||||
strokeColor='#FF645F'
|
||||
@ -146,7 +163,7 @@ export default function VaultDeposit(props: Props) {
|
||||
<div className='h-full w-[1px] rounded-xl bg-white/10'></div>
|
||||
<Gauge
|
||||
percentage={secondaryValuePercentage}
|
||||
tooltip={`${secondaryValuePercentage}% of value is ${props.secondaryAsset.symbol}`}
|
||||
tooltip={`${secondaryValuePercentage}% of value is ${secondaryAsset.symbol}`}
|
||||
labelClassName='text-martian-red'
|
||||
diameter={32}
|
||||
strokeColor='#FF645F'
|
||||
@ -156,13 +173,11 @@ export default function VaultDeposit(props: Props) {
|
||||
<div className='flex h-full flex-1 flex-col justify-between gap-6'>
|
||||
<TokenInput
|
||||
onChange={onChangePrimaryDeposit}
|
||||
amount={props.primaryAmount}
|
||||
amount={primaryCoin.amount}
|
||||
max={availablePrimaryAmount}
|
||||
maxText='Balance'
|
||||
asset={props.primaryAsset}
|
||||
warning={
|
||||
availablePrimaryAmount.isZero() ? getWarningText(props.primaryAsset) : undefined
|
||||
}
|
||||
asset={primaryAsset}
|
||||
warning={availablePrimaryAmount.isZero() ? getWarningText(primaryAsset) : undefined}
|
||||
disabled={disableInput}
|
||||
/>
|
||||
{!props.isCustomRatio && (
|
||||
@ -170,13 +185,11 @@ export default function VaultDeposit(props: Props) {
|
||||
)}
|
||||
<TokenInput
|
||||
onChange={onChangeSecondaryDeposit}
|
||||
amount={props.secondaryAmount}
|
||||
amount={secondaryCoin.amount}
|
||||
max={availableSecondaryAmount}
|
||||
maxText='Balance'
|
||||
asset={props.secondaryAsset}
|
||||
warning={
|
||||
availableSecondaryAmount.isZero() ? getWarningText(props.secondaryAsset) : undefined
|
||||
}
|
||||
asset={secondaryAsset}
|
||||
warning={availableSecondaryAmount.isZero() ? getWarningText(secondaryAsset) : undefined}
|
||||
disabled={disableInput}
|
||||
/>
|
||||
</div>
|
||||
@ -205,7 +218,7 @@ export default function VaultDeposit(props: Props) {
|
||||
<Switch checked={props.isCustomRatio} onChange={handleSwitch} name='customRatio' />
|
||||
</div>
|
||||
<div className='flex justify-between'>
|
||||
<Text className='text-white/50'>{`${props.primaryAsset.symbol}-${props.secondaryAsset.symbol} Deposit Value`}</Text>
|
||||
<Text className='text-white/50'>{`${primaryAsset.symbol}-${secondaryAsset.symbol} Deposit Value`}</Text>
|
||||
<DisplayCurrency
|
||||
coin={new BNCoin({ denom: baseCurrency.denom, amount: totalValue.toString() })}
|
||||
/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import Accordion from 'components/Accordion'
|
||||
import AccountSummary from 'components/Account/AccountSummary'
|
||||
@ -8,9 +8,9 @@ import VaultBorrowingsSubTitle from 'components/Modals/Vault/VaultBorrowingsSubT
|
||||
import VaultDeposit from 'components/Modals/Vault/VaultDeposits'
|
||||
import VaultDepositSubTitle from 'components/Modals/Vault/VaultDepositsSubTitle'
|
||||
import useIsOpenArray from 'hooks/useIsOpenArray'
|
||||
import useUpdateAccount from 'hooks/useUpdateAccount'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { BN } from 'utils/helpers'
|
||||
import useDepositVault from 'hooks/broadcast/useDepositVault'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
|
||||
interface Props {
|
||||
vault: Vault | DepositedVault
|
||||
@ -21,35 +21,30 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function VaultModalContent(props: Props) {
|
||||
const { updatedAccount, onChangeBorrowings, borrowings } = useUpdateAccount(
|
||||
props.account,
|
||||
props.vault,
|
||||
)
|
||||
const { addDebt, removeDeposits, addedDebt, removedDeposits, updatedAccount, addVaultValues } =
|
||||
useUpdatedAccount(props.account)
|
||||
|
||||
const [isOpen, toggleOpen] = useIsOpenArray(2, false)
|
||||
const [primaryAmount, setPrimaryAmount] = useState<BigNumber>(BN(0))
|
||||
const [secondaryAmount, setSecondaryAmount] = useState<BigNumber>(BN(0))
|
||||
const [isCustomRatio, setIsCustomRatio] = useState(false)
|
||||
|
||||
const deposits: BNCoin[] = useMemo(() => {
|
||||
const primaryBNCoin = new BNCoin({
|
||||
denom: props.vault.denoms.primary,
|
||||
amount: primaryAmount.toString(),
|
||||
})
|
||||
const secondaryBNCoin = new BNCoin({
|
||||
denom: props.vault.denoms.secondary,
|
||||
amount: secondaryAmount.toString(),
|
||||
})
|
||||
return [primaryBNCoin, secondaryBNCoin]
|
||||
}, [primaryAmount, secondaryAmount, props.vault.denoms.primary, props.vault.denoms.secondary])
|
||||
const {
|
||||
actions: depositActions,
|
||||
fee: depositFee,
|
||||
totalValue,
|
||||
} = useDepositVault({
|
||||
vault: props.vault,
|
||||
deposits: removedDeposits,
|
||||
borrowings: addedDebt,
|
||||
})
|
||||
|
||||
const onChangePrimaryAmount = useCallback(
|
||||
(amount: BigNumber) => setPrimaryAmount(amount.decimalPlaces(0)),
|
||||
[setPrimaryAmount],
|
||||
)
|
||||
const onChangeSecondaryAmount = useCallback(
|
||||
(amount: BigNumber) => setSecondaryAmount(amount.decimalPlaces(0)),
|
||||
[setSecondaryAmount],
|
||||
)
|
||||
useEffect(() => {
|
||||
addVaultValues([
|
||||
{
|
||||
address: props.vault.address,
|
||||
value: totalValue,
|
||||
},
|
||||
])
|
||||
}, [totalValue, addVaultValues, props.vault.address])
|
||||
|
||||
const onChangeIsCustomRatio = useCallback(
|
||||
(isCustomRatio: boolean) => setIsCustomRatio(isCustomRatio),
|
||||
@ -64,8 +59,12 @@ export default function VaultModalContent(props: Props) {
|
||||
|
||||
return (
|
||||
<VaultDepositSubTitle
|
||||
primaryAmount={primaryAmount}
|
||||
secondaryAmount={secondaryAmount}
|
||||
primaryAmount={
|
||||
removedDeposits.find((coin) => coin.denom === props.primaryAsset.denom)?.amount || BN(0)
|
||||
}
|
||||
secondaryAmount={
|
||||
removedDeposits.find((coin) => coin.denom === props.secondaryAsset.denom)?.amount || BN(0)
|
||||
}
|
||||
primaryAsset={props.primaryAsset}
|
||||
secondaryAsset={props.secondaryAsset}
|
||||
/>
|
||||
@ -78,7 +77,7 @@ export default function VaultModalContent(props: Props) {
|
||||
|
||||
if (isOpen[1]) return null
|
||||
|
||||
return <VaultBorrowingsSubTitle borrowings={borrowings} />
|
||||
return <VaultBorrowingsSubTitle borrowings={addedDebt} />
|
||||
}
|
||||
|
||||
return (
|
||||
@ -89,10 +88,8 @@ export default function VaultModalContent(props: Props) {
|
||||
{
|
||||
renderContent: () => (
|
||||
<VaultDeposit
|
||||
primaryAmount={primaryAmount}
|
||||
secondaryAmount={secondaryAmount}
|
||||
onChangePrimaryAmount={onChangePrimaryAmount}
|
||||
onChangeSecondaryAmount={onChangeSecondaryAmount}
|
||||
deposits={removedDeposits}
|
||||
onChangeDeposits={removeDeposits}
|
||||
primaryAsset={props.primaryAsset}
|
||||
secondaryAsset={props.secondaryAsset}
|
||||
account={props.account}
|
||||
@ -109,15 +106,15 @@ export default function VaultModalContent(props: Props) {
|
||||
{
|
||||
renderContent: () => (
|
||||
<VaultBorrowings
|
||||
account={updatedAccount}
|
||||
borrowings={borrowings}
|
||||
primaryAmount={primaryAmount}
|
||||
secondaryAmount={secondaryAmount}
|
||||
updatedAccount={updatedAccount}
|
||||
borrowings={addedDebt}
|
||||
deposits={removedDeposits}
|
||||
primaryAsset={props.primaryAsset}
|
||||
secondaryAsset={props.secondaryAsset}
|
||||
onChangeBorrowings={onChangeBorrowings}
|
||||
deposits={deposits}
|
||||
onChangeBorrowings={addDebt}
|
||||
vault={props.vault}
|
||||
depositActions={depositActions}
|
||||
depositFee={depositFee}
|
||||
/>
|
||||
),
|
||||
title: 'Borrow',
|
||||
|
@ -108,8 +108,8 @@ export const ASSETS: Asset[] = [
|
||||
logo: '/tokens/axlusdc.svg',
|
||||
decimals: 6,
|
||||
hasOraclePrice: true,
|
||||
isEnabled: true,
|
||||
isMarket: true,
|
||||
isEnabled: !IS_TESTNET,
|
||||
isMarket: !IS_TESTNET,
|
||||
isDisplayCurrency: true,
|
||||
isStable: true,
|
||||
poolId: 678,
|
||||
@ -132,4 +132,19 @@ export const ASSETS: Asset[] = [
|
||||
isStable: true,
|
||||
pythPriceFeedId: 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a',
|
||||
},
|
||||
{
|
||||
symbol: 'gamm/pool/6',
|
||||
name: 'OSMO-USDC.n Pool Token',
|
||||
id: 'gamm/pool/6',
|
||||
denom: 'gamm/pool/6',
|
||||
color: '',
|
||||
logo: '',
|
||||
decimals: 6,
|
||||
hasOraclePrice: true,
|
||||
isEnabled: true,
|
||||
isMarket: false,
|
||||
isDisplayCurrency: false,
|
||||
isStable: false,
|
||||
forceFetchPrice: true,
|
||||
},
|
||||
]
|
||||
|
@ -1,3 +1,6 @@
|
||||
import { VaultStatus } from 'types/enums/vault'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export const VAULT_DEPOSIT_BUFFER = 0.999
|
||||
|
||||
export const TESTNET_VAULTS_META_DATA: VaultMetaData[] = [
|
||||
@ -13,6 +16,7 @@ export const TESTNET_VAULTS_META_DATA: VaultMetaData[] = [
|
||||
primary: 'uosmo',
|
||||
secondary: 'ibc/B3504E092456BA618CC28AC671A71FB08C6CA0FD0BE7C8A5B5A3E2DD933CC9E4',
|
||||
lp: 'gamm/pool/6',
|
||||
vault: 'factory/osmo1q40xvrzpldwq5he4ftsf7zm2jf80tj373qaven38yqrvhex8r9rs8n94kv/cwVTT',
|
||||
},
|
||||
symbols: {
|
||||
primary: 'OSMO',
|
||||
@ -32,6 +36,7 @@ export const TESTNET_VAULTS_META_DATA: VaultMetaData[] = [
|
||||
primary: 'uosmo',
|
||||
secondary: 'ibc/B3504E092456BA618CC28AC671A71FB08C6CA0FD0BE7C8A5B5A3E2DD933CC9E4',
|
||||
lp: 'gamm/pool/6',
|
||||
vault: 'factory/osmo14lu7m4ganxs20258dazafrjfaulmfxruq9n0r0th90gs46jk3tuqwfkqwn/cwVTT',
|
||||
},
|
||||
symbols: {
|
||||
primary: 'OSMO',
|
||||
@ -51,6 +56,7 @@ export const TESTNET_VAULTS_META_DATA: VaultMetaData[] = [
|
||||
primary: 'uosmo',
|
||||
secondary: 'ibc/B3504E092456BA618CC28AC671A71FB08C6CA0FD0BE7C8A5B5A3E2DD933CC9E4',
|
||||
lp: 'gamm/pool/6',
|
||||
vault: 'factory/osmo1fmq9hw224fgz8lk48wyd0gfg028kvvzggt6c3zvnaqkw23x68cws5nd5em/cwVTT',
|
||||
},
|
||||
symbols: {
|
||||
primary: 'OSMO',
|
||||
@ -74,6 +80,7 @@ export const VAULTS_META_DATA: VaultMetaData[] = [
|
||||
primary: 'uosmo',
|
||||
secondary: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2',
|
||||
lp: 'gamm/pool/1',
|
||||
vault: 'factory/osmo1g3kmqpp8608szfp0pdag3r6z85npph7wmccat8lgl3mp407kv73qlj7qwp/cwVTT',
|
||||
},
|
||||
symbols: {
|
||||
primary: 'OSMO',
|
||||
@ -82,3 +89,28 @@ export const VAULTS_META_DATA: VaultMetaData[] = [
|
||||
isFeatured: true,
|
||||
},
|
||||
]
|
||||
|
||||
export const MOCK_DEPOSITED_VAULT_POSITION = {
|
||||
values: {
|
||||
primary: BN(0),
|
||||
secondary: BN(0),
|
||||
},
|
||||
amounts: {
|
||||
primary: BN(0),
|
||||
secondary: BN(0),
|
||||
locked: BN(0),
|
||||
unlocked: BN(0),
|
||||
unlocking: BN(0),
|
||||
},
|
||||
status: VaultStatus.ACTIVE,
|
||||
apy: null,
|
||||
ltv: {
|
||||
liq: 0,
|
||||
max: 0,
|
||||
},
|
||||
cap: {
|
||||
denom: '',
|
||||
max: BN(0),
|
||||
used: BN(0),
|
||||
},
|
||||
}
|
||||
|
@ -21,7 +21,12 @@ interface Props {
|
||||
deposits: BNCoin[]
|
||||
borrowings: BNCoin[]
|
||||
}
|
||||
export default function useDepositVault(props: Props): { actions: Action[]; fee: StdFee } {
|
||||
export default function useDepositVault(props: Props): {
|
||||
actions: Action[]
|
||||
fee: StdFee
|
||||
minLpToReceive: string
|
||||
totalValue: BigNumber
|
||||
} {
|
||||
const [minLpToReceive, setMinLpToReceive] = useState<BigNumber>(BN(0))
|
||||
const { data: prices } = usePrices()
|
||||
const [slippage] = useLocalStorage<number>(SLIPPAGE_KEY, DEFAULT_SETTINGS.slippage)
|
||||
@ -74,7 +79,8 @@ export default function useDepositVault(props: Props): { actions: Action[]; fee:
|
||||
])
|
||||
|
||||
const enterVaultActions: Action[] = useMemo(() => {
|
||||
if (primaryCoin.amount.isZero() || secondaryCoin.amount.isZero()) return []
|
||||
if (primaryCoin.amount.isZero() || secondaryCoin.amount.isZero() || minLpToReceive.isZero())
|
||||
return []
|
||||
|
||||
return getEnterVaultActions(props.vault, primaryCoin, secondaryCoin, minLpToReceive)
|
||||
}, [props.vault, primaryCoin, secondaryCoin, minLpToReceive])
|
||||
@ -84,5 +90,10 @@ export default function useDepositVault(props: Props): { actions: Action[]; fee:
|
||||
[borrowActions, swapActions, enterVaultActions],
|
||||
)
|
||||
|
||||
return { actions, fee: hardcodedFee }
|
||||
return {
|
||||
actions,
|
||||
fee: hardcodedFee,
|
||||
minLpToReceive: minLpToReceive.toString(),
|
||||
totalValue,
|
||||
}
|
||||
}
|
||||
|
9
src/hooks/useAccount.tsx
Normal file
9
src/hooks/useAccount.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import useSWR from 'swr'
|
||||
|
||||
import getAccount from 'api/accounts/getAccount'
|
||||
|
||||
export default function useAccounts(accountId?: string) {
|
||||
return useSWR(`account${accountId}`, () => getAccount(accountId || ''), {
|
||||
refreshInterval: 30000,
|
||||
})
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import useSWR from 'swr'
|
||||
|
||||
import getAccountDebts from 'api/accounts/getAccountDebts'
|
||||
|
||||
export default function useAccountDebts(accountId?: string) {
|
||||
return useSWR(`accountDebts${accountId}`, () => getAccountDebts(accountId || ''), {
|
||||
suspense: true,
|
||||
isPaused: () => !accountId,
|
||||
})
|
||||
}
|
9
src/hooks/useAssetParams.tsx
Normal file
9
src/hooks/useAssetParams.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import useSWR from 'swr'
|
||||
|
||||
import getAssetParams from 'api/params/getAssetParams'
|
||||
|
||||
export default function useAssetParams() {
|
||||
return useSWR('assetParams', getAssetParams, {
|
||||
fallbackData: [],
|
||||
})
|
||||
}
|
157
src/hooks/useHealthComputer.tsx
Normal file
157
src/hooks/useHealthComputer.tsx
Normal file
@ -0,0 +1,157 @@
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useAssetParams from 'hooks/useAssetParams'
|
||||
import {
|
||||
AssetParamsBaseForAddr,
|
||||
HealthComputer,
|
||||
} from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
|
||||
import { VaultConfigBaseForString } from 'types/generated/mars-params/MarsParams.types'
|
||||
import useVaultConfigs from 'hooks/useVaultConfigs'
|
||||
import {
|
||||
compute_health_js,
|
||||
max_borrow_estimate_js,
|
||||
max_withdraw_estimate_js,
|
||||
} from 'utils/health_computer'
|
||||
import { convertAccountToPositions } from 'utils/accounts'
|
||||
import { VaultPositionValue } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import useStore from 'store'
|
||||
|
||||
export default function useHealthComputer(account: Account) {
|
||||
const { data: prices } = usePrices()
|
||||
const { data: assetParams } = useAssetParams()
|
||||
const { data: vaultConfigs } = useVaultConfigs()
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
|
||||
const positions = useMemo(() => convertAccountToPositions(account), [account])
|
||||
const baseCurrencyPrice = useMemo(
|
||||
() => prices.find((price) => price.denom === baseCurrency.denom)?.amount || 0,
|
||||
[prices, baseCurrency.denom],
|
||||
)
|
||||
|
||||
const vaultPositionValues = useMemo(
|
||||
() =>
|
||||
account.vaults.reduce((prev, curr) => {
|
||||
const baseCoinPrice = prices.find((price) => price.denom === curr.denoms.lp)?.amount || 0
|
||||
prev[curr.address] = {
|
||||
base_coin: {
|
||||
amount: '0', // Not used by healthcomputer
|
||||
denom: curr.denoms.lp,
|
||||
value: curr.amounts.unlocking.times(baseCoinPrice).integerValue().toString(),
|
||||
},
|
||||
vault_coin: {
|
||||
amount: '0', // Not used by healthcomputer
|
||||
denom: curr.denoms.vault,
|
||||
value: curr.values.primary
|
||||
.div(baseCurrencyPrice)
|
||||
.plus(curr.values.secondary.div(baseCurrencyPrice))
|
||||
.integerValue()
|
||||
.toString(),
|
||||
},
|
||||
}
|
||||
return prev
|
||||
}, {} as { [key: string]: VaultPositionValue }),
|
||||
[account.vaults, prices, baseCurrencyPrice],
|
||||
)
|
||||
|
||||
const priceData = useMemo(() => {
|
||||
const baseCurrencyPrice =
|
||||
prices.find((price) => price.denom === baseCurrency.denom)?.amount || 0
|
||||
|
||||
return prices.reduce((prev, curr) => {
|
||||
prev[curr.denom] = curr.amount.div(baseCurrencyPrice).decimalPlaces(18).toString()
|
||||
return prev
|
||||
}, {} as { [key: string]: string })
|
||||
}, [prices, baseCurrency.denom])
|
||||
|
||||
const denomsData = useMemo(
|
||||
() =>
|
||||
assetParams.reduce((prev, curr) => {
|
||||
const params: AssetParamsBaseForAddr = {
|
||||
...curr,
|
||||
// The following overrides are required as testnet is 'broken' and new contracts are not updated yet
|
||||
// These overrides are not used by the healthcomputer internally, so they're not important anyways.
|
||||
protocol_liquidation_fee: '1',
|
||||
liquidation_bonus: {
|
||||
max_lb: '1',
|
||||
min_lb: '1',
|
||||
slope: '1',
|
||||
starting_lb: '1',
|
||||
},
|
||||
}
|
||||
prev[params.denom] = params
|
||||
|
||||
return prev
|
||||
}, {} as { [key: string]: AssetParamsBaseForAddr }),
|
||||
[assetParams],
|
||||
)
|
||||
|
||||
const vaultConfigsData = useMemo(() => {
|
||||
if (!positions || !vaultConfigs.length) return null
|
||||
|
||||
const vaultPositionDenoms = positions.vaults.map((vault) => vault.vault.address)
|
||||
return vaultConfigs
|
||||
.filter((config) => vaultPositionDenoms.includes(config.addr))
|
||||
.reduce((prev, curr) => {
|
||||
prev[curr.addr] = curr
|
||||
return prev
|
||||
}, {} as { [key: string]: VaultConfigBaseForString })
|
||||
}, [vaultConfigs, positions])
|
||||
|
||||
const healthComputer: HealthComputer | null = useMemo(() => {
|
||||
if (
|
||||
!positions ||
|
||||
!vaultPositionValues ||
|
||||
!vaultConfigsData ||
|
||||
Object.keys(denomsData).length === 0 ||
|
||||
Object.keys(priceData).length === 0 ||
|
||||
positions.vaults.length !== Object.keys(vaultPositionValues).length
|
||||
)
|
||||
return null
|
||||
|
||||
return {
|
||||
denoms_data: { params: denomsData, prices: priceData },
|
||||
vaults_data: {
|
||||
vault_configs: vaultConfigsData,
|
||||
vault_values: vaultPositionValues,
|
||||
},
|
||||
positions: positions,
|
||||
kind: 'default',
|
||||
}
|
||||
}, [priceData, denomsData, vaultConfigsData, vaultPositionValues, positions])
|
||||
|
||||
const computeHealth = useCallback(() => {
|
||||
async function callComputeHealthWasmFn(): Promise<number> {
|
||||
if (!healthComputer) return 0
|
||||
return Number((await compute_health_js(healthComputer)).max_ltv_health_factor) || 0
|
||||
}
|
||||
|
||||
return callComputeHealthWasmFn()
|
||||
}, [healthComputer])
|
||||
|
||||
const computeMaxBorrowAmount = useCallback(
|
||||
(denom: string) => {
|
||||
async function callMaxBorrowWasmFn(denom: string): Promise<number> {
|
||||
if (!healthComputer) return 0
|
||||
return await max_borrow_estimate_js(healthComputer, denom)
|
||||
}
|
||||
|
||||
return callMaxBorrowWasmFn(denom)
|
||||
},
|
||||
[healthComputer],
|
||||
)
|
||||
|
||||
const computeMaxWithdrawAmount = useCallback(
|
||||
(denom: string) => {
|
||||
async function callMaxWithdrawWasmFn(denom: string): Promise<number> {
|
||||
if (!healthComputer) return 0
|
||||
return await max_withdraw_estimate_js(healthComputer, denom)
|
||||
}
|
||||
|
||||
return callMaxWithdrawWasmFn(denom)
|
||||
},
|
||||
[healthComputer],
|
||||
)
|
||||
|
||||
return { computeHealth, computeMaxBorrowAmount, computeMaxWithdrawAmount }
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export default function useUpdateAccount(account: Account, vault: Vault) {
|
||||
const [updatedAccount, setUpdatedAccount] = useState<Account>(account)
|
||||
const [borrowings, setBorrowings] = useState<BNCoin[]>([])
|
||||
|
||||
function getCoin(denom: string, amount: BigNumber): Coin {
|
||||
return {
|
||||
denom,
|
||||
amount: amount.decimalPlaces(0).toString(),
|
||||
}
|
||||
}
|
||||
|
||||
const onChangeBorrowings = useCallback(
|
||||
(borrowings: BNCoin[]) => {
|
||||
const debts: Coin[] = [...account.debts]
|
||||
const deposits: Coin[] = [...account.deposits]
|
||||
const currentDebtDenoms = debts.map((debt) => debt.denom)
|
||||
const currentDepositDenoms = deposits.map((deposit) => deposit.denom)
|
||||
|
||||
borrowings.map((coin) => {
|
||||
if (coin.amount.isZero()) return
|
||||
|
||||
if (currentDebtDenoms.includes(coin.denom)) {
|
||||
const index = currentDebtDenoms.indexOf(coin.denom)
|
||||
const newAmount = BN(debts[index].amount).plus(coin.amount)
|
||||
debts[index] = getCoin(coin.denom, newAmount)
|
||||
} else {
|
||||
debts.push(coin.toCoin())
|
||||
}
|
||||
|
||||
if (currentDepositDenoms.includes(coin.denom)) {
|
||||
const index = currentDepositDenoms.indexOf(coin.denom)
|
||||
const newAmount = BN(deposits[index].amount).plus(coin.amount)
|
||||
deposits[index] = getCoin(coin.denom, newAmount)
|
||||
} else {
|
||||
deposits.push(coin.toCoin())
|
||||
}
|
||||
})
|
||||
|
||||
setBorrowings(borrowings)
|
||||
setUpdatedAccount({
|
||||
...account,
|
||||
debts,
|
||||
deposits,
|
||||
})
|
||||
},
|
||||
[account],
|
||||
)
|
||||
|
||||
return { borrowings, updatedAccount, onChangeBorrowings }
|
||||
}
|
69
src/hooks/useUpdatedAccount/functions.ts
Normal file
69
src/hooks/useUpdatedAccount/functions.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { VaultValue } from 'hooks/useUpdatedAccount'
|
||||
import { getVaultMetaData } from 'utils/vaults'
|
||||
import { MOCK_DEPOSITED_VAULT_POSITION } from 'constants/vaults'
|
||||
|
||||
export function addCoins(additionalCoins: BNCoin[], currentCoins: BNCoin[]) {
|
||||
const currentDenoms = currentCoins.map((coin) => coin.denom)
|
||||
|
||||
additionalCoins.forEach((coin) => {
|
||||
if (coin.amount.isZero()) return
|
||||
|
||||
if (currentDenoms.includes(coin.denom)) {
|
||||
const index = currentDenoms.indexOf(coin.denom)
|
||||
currentCoins[index].amount = BN(currentCoins[index].amount).plus(coin.amount)
|
||||
} else {
|
||||
currentCoins.push(coin)
|
||||
}
|
||||
})
|
||||
|
||||
return currentCoins
|
||||
}
|
||||
|
||||
export function removeCoins(coinsToRemove: BNCoin[], currentCoins: BNCoin[]) {
|
||||
const currentDenoms = currentCoins.map((coin) => coin.denom)
|
||||
|
||||
coinsToRemove.forEach((coin) => {
|
||||
if (coin.amount.isZero()) return
|
||||
if (!currentDenoms.includes(coin.denom)) return
|
||||
|
||||
const index = currentDenoms.indexOf(coin.denom)
|
||||
currentCoins[index].amount = BN(currentCoins[index].amount).minus(coin.amount)
|
||||
})
|
||||
|
||||
return currentCoins
|
||||
}
|
||||
|
||||
export function addValueToVaults(
|
||||
vaultValues: VaultValue[],
|
||||
vaults: DepositedVault[],
|
||||
): DepositedVault[] {
|
||||
const currentVaultAddresses = vaults.map((vault) => vault.address)
|
||||
|
||||
vaultValues.forEach((vaultValue) => {
|
||||
if (vaultValue.value.isZero()) return
|
||||
const halfValue = vaultValue.value.div(2)
|
||||
|
||||
if (currentVaultAddresses.includes(vaultValue.address)) {
|
||||
const index = currentVaultAddresses.indexOf(vaultValue.address)
|
||||
vaults[index].values.primary = BN(vaults[index].values.primary).plus(halfValue)
|
||||
vaults[index].values.secondary = BN(vaults[index].values.secondary).plus(halfValue)
|
||||
} else {
|
||||
const vaultMetaData = getVaultMetaData(vaultValue.address)
|
||||
|
||||
if (!vaultMetaData) return
|
||||
|
||||
vaults.push({
|
||||
...vaultMetaData,
|
||||
...MOCK_DEPOSITED_VAULT_POSITION,
|
||||
values: {
|
||||
primary: halfValue,
|
||||
secondary: halfValue,
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return vaults
|
||||
}
|
46
src/hooks/useUpdatedAccount/index.ts
Normal file
46
src/hooks/useUpdatedAccount/index.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { addCoins, addValueToVaults, removeCoins } from 'hooks/useUpdatedAccount/functions'
|
||||
import { cloneAccount } from 'utils/accounts'
|
||||
|
||||
export interface VaultValue {
|
||||
address: string
|
||||
value: BigNumber
|
||||
}
|
||||
|
||||
export function useUpdatedAccount(account: Account) {
|
||||
const [updatedAccount, setUpdatedAccount] = useState<Account>(cloneAccount(account))
|
||||
const [addedDeposits, addDeposits] = useState<BNCoin[]>([])
|
||||
const [removedDeposits, removeDeposits] = useState<BNCoin[]>([])
|
||||
const [addedDebt, addDebt] = useState<BNCoin[]>([])
|
||||
const [removedDebt, removeDebt] = useState<BNCoin[]>([])
|
||||
const [addedVaultValues, addVaultValues] = useState<VaultValue[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
async function updateAccount() {
|
||||
const accountCopy = cloneAccount(account)
|
||||
accountCopy.deposits = addCoins(addedDeposits, [...accountCopy.deposits])
|
||||
accountCopy.debts = addCoins(addedDebt, [...accountCopy.debts])
|
||||
accountCopy.vaults = addValueToVaults(addedVaultValues, [...accountCopy.vaults])
|
||||
accountCopy.deposits = removeCoins(removedDeposits, [...accountCopy.deposits])
|
||||
accountCopy.debts = removeCoins(removedDebt, [...accountCopy.debts])
|
||||
setUpdatedAccount(accountCopy)
|
||||
}
|
||||
|
||||
updateAccount()
|
||||
}, [account, addedDebt, removedDebt, addedDeposits, removedDeposits, addedVaultValues])
|
||||
|
||||
return {
|
||||
updatedAccount,
|
||||
addDeposits,
|
||||
removeDeposits,
|
||||
addDebt,
|
||||
removeDebt,
|
||||
addVaultValues,
|
||||
addedDeposits,
|
||||
addedDebt,
|
||||
removedDeposits,
|
||||
removedDebt,
|
||||
}
|
||||
}
|
9
src/hooks/useVaultConfigs.tsx
Normal file
9
src/hooks/useVaultConfigs.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import useSWR from 'swr'
|
||||
|
||||
import { getVaultConfigs } from 'api/vaults/getVaultConfigs'
|
||||
|
||||
export default function useVaultConfigs() {
|
||||
return useSWR('vaultConfigs', getVaultConfigs, {
|
||||
fallbackData: [],
|
||||
})
|
||||
}
|
@ -2,6 +2,7 @@ import { AppProps } from 'next/app'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import DefaultPageHead from 'components/DefaultPageHead'
|
||||
import init from 'utils/health_computer'
|
||||
|
||||
import 'react-toastify/dist/ReactToastify.min.css'
|
||||
import 'styles/globals.css'
|
||||
@ -9,6 +10,14 @@ import 'styles/globals.css'
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
const PageComponent = Component as any
|
||||
const [isServer, setIsServer] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
const loadHealthComputerWasm = async () => {
|
||||
await init()
|
||||
}
|
||||
loadHealthComputerWasm()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
setIsServer(false)
|
||||
}, [])
|
||||
|
@ -47,8 +47,9 @@ export interface DenomsData {
|
||||
export interface AssetParamsBaseForAddr {
|
||||
credit_manager: CmSettingsForAddr
|
||||
denom: string
|
||||
liquidation_bonus: Decimal
|
||||
liquidation_bonus: LiquidationBonus
|
||||
liquidation_threshold: Decimal
|
||||
protocol_liquidation_fee: Decimal
|
||||
max_loan_to_value: Decimal
|
||||
red_bank: RedBankSettings
|
||||
}
|
||||
@ -128,3 +129,10 @@ export interface CoinValue {
|
||||
denom: string
|
||||
value: Uint128
|
||||
}
|
||||
|
||||
export interface LiquidationBonus {
|
||||
max_lb: Decimal
|
||||
min_lb: Decimal
|
||||
slope: Decimal
|
||||
starting_lb: Decimal
|
||||
}
|
||||
|
4
src/types/interfaces/account.d.ts
vendored
4
src/types/interfaces/account.d.ts
vendored
@ -3,14 +3,14 @@ interface Account extends AccountChange {
|
||||
deposits: BNCoin[]
|
||||
debts: BNCoin[]
|
||||
lends: BNCoin[]
|
||||
vaults: import('types/generated/mars-mock-credit-manager/MarsMockCreditManager.types').ArrayOfVaultInfoResponse
|
||||
vaults: DepositedVault[]
|
||||
}
|
||||
|
||||
interface AccountChange {
|
||||
deposits?: BNCoin[]
|
||||
debts?: BNCoin[]
|
||||
lends?: BNCoin[]
|
||||
vaults?: import('types/generated/mars-mock-credit-manager/MarsMockCreditManager.types').ArrayOfVaultInfoResponse
|
||||
vaults?: DepositedVault[]
|
||||
}
|
||||
|
||||
interface AccountBalanceRow {
|
||||
|
22
src/types/interfaces/asset.d.ts
vendored
22
src/types/interfaces/asset.d.ts
vendored
@ -2,8 +2,26 @@ interface Asset {
|
||||
color: string
|
||||
name: string
|
||||
denom: string
|
||||
symbol: 'OSMO' | 'ATOM' | 'MARS' | 'stATOM' | 'USDC.axl' | 'USDC.n' | 'WBTC.axl' | 'WETH.axl'
|
||||
id: 'OSMO' | 'ATOM' | 'MARS' | 'stATOM' | 'axlUSDC' | 'axlWBTC' | 'axlWETH' | 'nUSDC'
|
||||
symbol:
|
||||
| 'OSMO'
|
||||
| 'ATOM'
|
||||
| 'MARS'
|
||||
| 'stATOM'
|
||||
| 'USDC.axl'
|
||||
| 'USDC.n'
|
||||
| 'WBTC.axl'
|
||||
| 'WETH.axl'
|
||||
| 'gamm/pool/6'
|
||||
id:
|
||||
| 'OSMO'
|
||||
| 'ATOM'
|
||||
| 'MARS'
|
||||
| 'stATOM'
|
||||
| 'axlUSDC'
|
||||
| 'axlWBTC'
|
||||
| 'axlWETH'
|
||||
| 'nUSDC'
|
||||
| 'gamm/pool/6'
|
||||
prefix?: string
|
||||
contract_addr?: string
|
||||
logo: string
|
||||
|
1
src/types/interfaces/vaults.d.ts
vendored
1
src/types/interfaces/vaults.d.ts
vendored
@ -11,6 +11,7 @@ interface VaultMetaData {
|
||||
primary: string
|
||||
secondary: string
|
||||
lp: string
|
||||
vault: string
|
||||
}
|
||||
symbols: {
|
||||
primary: string
|
||||
|
@ -1,8 +1,11 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
import {
|
||||
Positions,
|
||||
VaultPosition,
|
||||
} from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { BN, getApproximateHourlyInterest } from 'utils/helpers'
|
||||
import { getTokenValue } from 'utils/tokens'
|
||||
|
||||
export const calculateAccountBalance = (
|
||||
account: Account | AccountChange,
|
||||
@ -25,6 +28,7 @@ export const calculateAccountDeposits = (
|
||||
return acc.plus(depositValue)
|
||||
}, BN(0))
|
||||
}
|
||||
|
||||
export const calculateAccountDebt = (
|
||||
account: Account | AccountChange,
|
||||
prices: BNCoin[],
|
||||
@ -63,34 +67,73 @@ export function getAmount(denom: string, coins: Coin[]): BigNumber {
|
||||
return BN(coins.find((asset) => asset.denom === denom)?.amount ?? 0)
|
||||
}
|
||||
|
||||
export function getNetCollateralValue(account: Account, marketAssets: Market[], prices: BNCoin[]) {
|
||||
const depositCollateralValue = account.deposits.reduce((acc, coin) => {
|
||||
const asset = marketAssets.find((asset) => asset.denom === coin.denom)
|
||||
|
||||
if (!asset) return acc
|
||||
|
||||
const marketValue = BN(getTokenValue(coin, prices))
|
||||
const collateralValue = marketValue.multipliedBy(asset.maxLtv)
|
||||
|
||||
return collateralValue.plus(acc)
|
||||
}, BN(0))
|
||||
|
||||
// Implement Vault Collateral calculation (MP-2915)
|
||||
|
||||
const liabilitiesValue = account.debts.reduce((acc, coin) => {
|
||||
const asset = marketAssets.find((asset) => asset.denom === coin.denom)
|
||||
|
||||
if (!asset) return acc
|
||||
|
||||
const estimatedInterestAmount = getApproximateHourlyInterest(coin.amount, asset.borrowRate)
|
||||
const liability = BN(getTokenValue(coin, prices)).plus(estimatedInterestAmount)
|
||||
|
||||
return liability.plus(acc)
|
||||
}, BN(0))
|
||||
|
||||
if (liabilitiesValue.isGreaterThan(depositCollateralValue)) {
|
||||
return BN(0)
|
||||
export function convertAccountToPositions(account: Account): Positions {
|
||||
return {
|
||||
account_id: account.id,
|
||||
debts: account.debts.map((debt) => ({
|
||||
shares: '0', // This is not needed, but required by the contract
|
||||
amount: debt.amount.toString(),
|
||||
denom: debt.denom,
|
||||
})),
|
||||
deposits: account.deposits.map((deposit) => deposit.toCoin()),
|
||||
lends: account.lends.map((lend) => ({
|
||||
shares: '0', // This is not needed, but required by the contract
|
||||
amount: lend.amount.toString(),
|
||||
denom: lend.denom,
|
||||
})),
|
||||
vaults: account.vaults.map(
|
||||
(vault) =>
|
||||
({
|
||||
vault: {
|
||||
address: vault.address,
|
||||
},
|
||||
amount: {
|
||||
locking: {
|
||||
locked: vault.amounts.locked.toString(),
|
||||
unlocking: [
|
||||
{
|
||||
id: 0,
|
||||
coin: { amount: vault.amounts.unlocking.toString(), denom: vault.denoms.lp },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
} as VaultPosition),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
export function cloneAccount(account: Account): Account {
|
||||
return {
|
||||
id: account.id,
|
||||
debts: account.debts.map(
|
||||
(debt) =>
|
||||
new BNCoin({
|
||||
amount: debt.amount.toString(),
|
||||
denom: debt.denom,
|
||||
}),
|
||||
),
|
||||
deposits: account.deposits.map((deposit) => new BNCoin(deposit.toCoin())),
|
||||
lends: account.lends.map(
|
||||
(lend) =>
|
||||
new BNCoin({
|
||||
amount: lend.amount.toString(),
|
||||
denom: lend.denom,
|
||||
}),
|
||||
),
|
||||
vaults: account.vaults.map((vault) => ({
|
||||
...vault,
|
||||
amounts: {
|
||||
locked: BN(vault.amounts.locked),
|
||||
unlocking: BN(vault.amounts.unlocking),
|
||||
unlocked: BN(vault.amounts.unlocked),
|
||||
primary: BN(vault.amounts.primary),
|
||||
secondary: BN(vault.amounts.secondary),
|
||||
},
|
||||
values: {
|
||||
primary: BN(vault.values.primary),
|
||||
secondary: BN(vault.values.secondary),
|
||||
},
|
||||
})),
|
||||
}
|
||||
|
||||
return depositCollateralValue.minus(liabilitiesValue)
|
||||
}
|
||||
|
60
src/utils/health_computer/index.d.ts
vendored
Normal file
60
src/utils/health_computer/index.d.ts
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* @param {any} health_computer
|
||||
* @returns {any}
|
||||
*/
|
||||
export function compute_health_js(health_computer: any): any
|
||||
/**
|
||||
* @param {any} health_computer
|
||||
* @param {any} withdraw_denom
|
||||
* @returns {HealthResponse}
|
||||
*/
|
||||
export function max_withdraw_estimate_js(health_computer: any, withdraw_denom: any): any
|
||||
/**
|
||||
* @param {any} health_computer
|
||||
* @param {any} borrow_denom
|
||||
* @returns {any}
|
||||
*/
|
||||
export function max_borrow_estimate_js(health_computer: any, borrow_denom: any): any
|
||||
|
||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module
|
||||
|
||||
export interface InitOutput {
|
||||
readonly memory: WebAssembly.Memory
|
||||
readonly compute_health_js: (a: number) => number
|
||||
readonly max_withdraw_estimate_js: (a: number, b: number) => number
|
||||
readonly max_borrow_estimate_js: (a: number, b: number) => number
|
||||
readonly allocate: (a: number) => number
|
||||
readonly deallocate: (a: number) => void
|
||||
readonly requires_stargate: () => void
|
||||
readonly requires_iterator: () => void
|
||||
readonly interface_version_8: () => void
|
||||
readonly __wbindgen_malloc: (a: number, b: number) => number
|
||||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number
|
||||
readonly __wbindgen_free: (a: number, b: number, c: number) => void
|
||||
readonly __wbindgen_exn_store: (a: number) => void
|
||||
}
|
||||
|
||||
export type SyncInitInput = BufferSource | WebAssembly.Module
|
||||
/**
|
||||
* Instantiates the given `module`, which can either be bytes or
|
||||
* a precompiled `WebAssembly.Module`.
|
||||
*
|
||||
* @param {SyncInitInput} module
|
||||
*
|
||||
* @returns {InitOutput}
|
||||
*/
|
||||
export function initSync(module: SyncInitInput): InitOutput
|
||||
|
||||
/**
|
||||
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
||||
* for everything else, calls `WebAssembly.instantiate` directly.
|
||||
*
|
||||
* @param {InitInput | Promise<InitInput>} module_or_path
|
||||
*
|
||||
* @returns {Promise<InitOutput>}
|
||||
*/
|
||||
export default function __wbg_init(
|
||||
module_or_path?: InitInput | Promise<InitInput>,
|
||||
): Promise<InitOutput>
|
568
src/utils/health_computer/index.js
Normal file
568
src/utils/health_computer/index.js
Normal file
@ -0,0 +1,568 @@
|
||||
let wasm
|
||||
|
||||
const heap = new Array(128).fill(undefined)
|
||||
|
||||
heap.push(undefined, null, true, false)
|
||||
|
||||
function getObject(idx) {
|
||||
return heap[idx]
|
||||
}
|
||||
|
||||
let heap_next = heap.length
|
||||
|
||||
function dropObject(idx) {
|
||||
if (idx < 132) return
|
||||
heap[idx] = heap_next
|
||||
heap_next = idx
|
||||
}
|
||||
|
||||
function takeObject(idx) {
|
||||
const ret = getObject(idx)
|
||||
dropObject(idx)
|
||||
return ret
|
||||
}
|
||||
|
||||
let WASM_VECTOR_LEN = 0
|
||||
|
||||
let cachedUint8Memory0 = null
|
||||
|
||||
function getUint8Memory0() {
|
||||
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
|
||||
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer)
|
||||
}
|
||||
return cachedUint8Memory0
|
||||
}
|
||||
|
||||
const cachedTextEncoder =
|
||||
typeof TextEncoder !== 'undefined'
|
||||
? new TextEncoder('utf-8')
|
||||
: {
|
||||
encode: () => {
|
||||
throw Error('TextEncoder not available')
|
||||
},
|
||||
}
|
||||
|
||||
const encodeString =
|
||||
typeof cachedTextEncoder.encodeInto === 'function'
|
||||
? function (arg, view) {
|
||||
return cachedTextEncoder.encodeInto(arg, view)
|
||||
}
|
||||
: function (arg, view) {
|
||||
const buf = cachedTextEncoder.encode(arg)
|
||||
view.set(buf)
|
||||
return {
|
||||
read: arg.length,
|
||||
written: buf.length,
|
||||
}
|
||||
}
|
||||
|
||||
function passStringToWasm0(arg, malloc, realloc) {
|
||||
if (realloc === undefined) {
|
||||
const buf = cachedTextEncoder.encode(arg)
|
||||
const ptr = malloc(buf.length, 1) >>> 0
|
||||
getUint8Memory0()
|
||||
.subarray(ptr, ptr + buf.length)
|
||||
.set(buf)
|
||||
WASM_VECTOR_LEN = buf.length
|
||||
return ptr
|
||||
}
|
||||
|
||||
let len = arg.length
|
||||
let ptr = malloc(len, 1) >>> 0
|
||||
|
||||
const mem = getUint8Memory0()
|
||||
|
||||
let offset = 0
|
||||
|
||||
for (; offset < len; offset++) {
|
||||
const code = arg.charCodeAt(offset)
|
||||
if (code > 0x7f) break
|
||||
mem[ptr + offset] = code
|
||||
}
|
||||
|
||||
if (offset !== len) {
|
||||
if (offset !== 0) {
|
||||
arg = arg.slice(offset)
|
||||
}
|
||||
ptr = realloc(ptr, len, (len = offset + arg.length * 3), 1) >>> 0
|
||||
const view = getUint8Memory0().subarray(ptr + offset, ptr + len)
|
||||
const ret = encodeString(arg, view)
|
||||
|
||||
offset += ret.written
|
||||
}
|
||||
|
||||
WASM_VECTOR_LEN = offset
|
||||
return ptr
|
||||
}
|
||||
|
||||
function isLikeNone(x) {
|
||||
return x === undefined || x === null
|
||||
}
|
||||
|
||||
let cachedInt32Memory0 = null
|
||||
|
||||
function getInt32Memory0() {
|
||||
if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) {
|
||||
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer)
|
||||
}
|
||||
return cachedInt32Memory0
|
||||
}
|
||||
|
||||
const cachedTextDecoder =
|
||||
typeof TextDecoder !== 'undefined'
|
||||
? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true })
|
||||
: {
|
||||
decode: () => {
|
||||
throw Error('TextDecoder not available')
|
||||
},
|
||||
}
|
||||
|
||||
if (typeof TextDecoder !== 'undefined') {
|
||||
cachedTextDecoder.decode()
|
||||
}
|
||||
|
||||
function getStringFromWasm0(ptr, len) {
|
||||
ptr = ptr >>> 0
|
||||
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len))
|
||||
}
|
||||
|
||||
function addHeapObject(obj) {
|
||||
if (heap_next === heap.length) heap.push(heap.length + 1)
|
||||
const idx = heap_next
|
||||
heap_next = heap[idx]
|
||||
|
||||
heap[idx] = obj
|
||||
return idx
|
||||
}
|
||||
|
||||
let cachedFloat64Memory0 = null
|
||||
|
||||
function getFloat64Memory0() {
|
||||
if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) {
|
||||
cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer)
|
||||
}
|
||||
return cachedFloat64Memory0
|
||||
}
|
||||
|
||||
let cachedBigInt64Memory0 = null
|
||||
|
||||
function getBigInt64Memory0() {
|
||||
if (cachedBigInt64Memory0 === null || cachedBigInt64Memory0.byteLength === 0) {
|
||||
cachedBigInt64Memory0 = new BigInt64Array(wasm.memory.buffer)
|
||||
}
|
||||
return cachedBigInt64Memory0
|
||||
}
|
||||
|
||||
function debugString(val) {
|
||||
// primitive types
|
||||
const type = typeof val
|
||||
if (type == 'number' || type == 'boolean' || val == null) {
|
||||
return `${val}`
|
||||
}
|
||||
if (type == 'string') {
|
||||
return `"${val}"`
|
||||
}
|
||||
if (type == 'symbol') {
|
||||
const description = val.description
|
||||
if (description == null) {
|
||||
return 'Symbol'
|
||||
} else {
|
||||
return `Symbol(${description})`
|
||||
}
|
||||
}
|
||||
if (type == 'function') {
|
||||
const name = val.name
|
||||
if (typeof name == 'string' && name.length > 0) {
|
||||
return `Function(${name})`
|
||||
} else {
|
||||
return 'Function'
|
||||
}
|
||||
}
|
||||
// objects
|
||||
if (Array.isArray(val)) {
|
||||
const length = val.length
|
||||
let debug = '['
|
||||
if (length > 0) {
|
||||
debug += debugString(val[0])
|
||||
}
|
||||
for (let i = 1; i < length; i++) {
|
||||
debug += ', ' + debugString(val[i])
|
||||
}
|
||||
debug += ']'
|
||||
return debug
|
||||
}
|
||||
// Test for built-in
|
||||
const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val))
|
||||
let className
|
||||
if (builtInMatches.length > 1) {
|
||||
className = builtInMatches[1]
|
||||
} else {
|
||||
// Failed to match the standard '[object ClassName]'
|
||||
return toString.call(val)
|
||||
}
|
||||
if (className == 'Object') {
|
||||
// we're a user defined class or Object
|
||||
// JSON.stringify avoids problems with cycles, and is generally much
|
||||
// easier than looping through ownProperties of `val`.
|
||||
try {
|
||||
return 'Object(' + JSON.stringify(val) + ')'
|
||||
} catch (_) {
|
||||
return 'Object'
|
||||
}
|
||||
}
|
||||
// errors
|
||||
if (val instanceof Error) {
|
||||
return `${val.name}: ${val.message}\n${val.stack}`
|
||||
}
|
||||
// TODO we could test for more things here, like `Set`s and `Map`s.
|
||||
return className
|
||||
}
|
||||
/**
|
||||
* @param {any} health_computer
|
||||
* @returns {any}
|
||||
*/
|
||||
export function compute_health_js(health_computer) {
|
||||
const ret = wasm.compute_health_js(addHeapObject(health_computer))
|
||||
return takeObject(ret)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} health_computer
|
||||
* @param {any} withdraw_denom
|
||||
* @returns {any}
|
||||
*/
|
||||
export function max_withdraw_estimate_js(health_computer, withdraw_denom) {
|
||||
const ret = wasm.max_withdraw_estimate_js(
|
||||
addHeapObject(health_computer),
|
||||
addHeapObject(withdraw_denom),
|
||||
)
|
||||
return takeObject(ret)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} health_computer
|
||||
* @param {any} borrow_denom
|
||||
* @returns {any}
|
||||
*/
|
||||
export function max_borrow_estimate_js(health_computer, borrow_denom) {
|
||||
const ret = wasm.max_borrow_estimate_js(
|
||||
addHeapObject(health_computer),
|
||||
addHeapObject(borrow_denom),
|
||||
)
|
||||
return takeObject(ret)
|
||||
}
|
||||
|
||||
function handleError(f, args) {
|
||||
try {
|
||||
return f.apply(this, args)
|
||||
} catch (e) {
|
||||
wasm.__wbindgen_exn_store(addHeapObject(e))
|
||||
}
|
||||
}
|
||||
|
||||
async function __wbg_load(module, imports) {
|
||||
if (typeof Response === 'function' && module instanceof Response) {
|
||||
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||
try {
|
||||
return await WebAssembly.instantiateStreaming(module, imports)
|
||||
} catch (e) {
|
||||
if (module.headers.get('Content-Type') != 'application/wasm') {
|
||||
console.warn(
|
||||
'`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n',
|
||||
e,
|
||||
)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bytes = await module.arrayBuffer()
|
||||
return await WebAssembly.instantiate(bytes, imports)
|
||||
} else {
|
||||
const instance = await WebAssembly.instantiate(module, imports)
|
||||
|
||||
if (instance instanceof WebAssembly.Instance) {
|
||||
return { instance, module }
|
||||
} else {
|
||||
return instance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function __wbg_get_imports() {
|
||||
const imports = {}
|
||||
imports.wbg = {}
|
||||
imports.wbg.__wbindgen_object_drop_ref = function (arg0) {
|
||||
takeObject(arg0)
|
||||
}
|
||||
imports.wbg.__wbindgen_is_object = function (arg0) {
|
||||
const val = getObject(arg0)
|
||||
const ret = typeof val === 'object' && val !== null
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbindgen_is_undefined = function (arg0) {
|
||||
const ret = getObject(arg0) === undefined
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbindgen_in = function (arg0, arg1) {
|
||||
const ret = getObject(arg0) in getObject(arg1)
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbindgen_string_get = function (arg0, arg1) {
|
||||
const obj = getObject(arg1)
|
||||
const ret = typeof obj === 'string' ? obj : undefined
|
||||
var ptr1 = isLikeNone(ret)
|
||||
? 0
|
||||
: passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc)
|
||||
var len1 = WASM_VECTOR_LEN
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len1
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr1
|
||||
}
|
||||
imports.wbg.__wbindgen_error_new = function (arg0, arg1) {
|
||||
const ret = new Error(getStringFromWasm0(arg0, arg1))
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbindgen_is_string = function (arg0) {
|
||||
const ret = typeof getObject(arg0) === 'string'
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbindgen_boolean_get = function (arg0) {
|
||||
const v = getObject(arg0)
|
||||
const ret = typeof v === 'boolean' ? (v ? 1 : 0) : 2
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbindgen_is_bigint = function (arg0) {
|
||||
const ret = typeof getObject(arg0) === 'bigint'
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbindgen_bigint_from_u64 = function (arg0) {
|
||||
const ret = BigInt.asUintN(64, arg0)
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbindgen_jsval_eq = function (arg0, arg1) {
|
||||
const ret = getObject(arg0) === getObject(arg1)
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbg_new_abda76e883ba8a5f = function () {
|
||||
const ret = new Error()
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_stack_658279fe44541cf6 = function (arg0, arg1) {
|
||||
const ret = getObject(arg1).stack
|
||||
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc)
|
||||
const len1 = WASM_VECTOR_LEN
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len1
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr1
|
||||
}
|
||||
imports.wbg.__wbg_error_f851667af71bcfc6 = function (arg0, arg1) {
|
||||
let deferred0_0
|
||||
let deferred0_1
|
||||
try {
|
||||
deferred0_0 = arg0
|
||||
deferred0_1 = arg1
|
||||
console.error(getStringFromWasm0(arg0, arg1))
|
||||
} finally {
|
||||
wasm.__wbindgen_free(deferred0_0, deferred0_1, 1)
|
||||
}
|
||||
}
|
||||
imports.wbg.__wbindgen_jsval_loose_eq = function (arg0, arg1) {
|
||||
const ret = getObject(arg0) == getObject(arg1)
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbindgen_number_get = function (arg0, arg1) {
|
||||
const obj = getObject(arg1)
|
||||
const ret = typeof obj === 'number' ? obj : undefined
|
||||
getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret
|
||||
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret)
|
||||
}
|
||||
imports.wbg.__wbindgen_object_clone_ref = function (arg0) {
|
||||
const ret = getObject(arg0)
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbindgen_string_new = function (arg0, arg1) {
|
||||
const ret = getStringFromWasm0(arg0, arg1)
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_getwithrefkey_5e6d9547403deab8 = function (arg0, arg1) {
|
||||
const ret = getObject(arg0)[getObject(arg1)]
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_set_841ac57cff3d672b = function (arg0, arg1, arg2) {
|
||||
getObject(arg0)[takeObject(arg1)] = takeObject(arg2)
|
||||
}
|
||||
imports.wbg.__wbg_get_44be0491f933a435 = function (arg0, arg1) {
|
||||
const ret = getObject(arg0)[arg1 >>> 0]
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_length_fff51ee6522a1a18 = function (arg0) {
|
||||
const ret = getObject(arg0).length
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbindgen_is_function = function (arg0) {
|
||||
const ret = typeof getObject(arg0) === 'function'
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbg_next_526fc47e980da008 = function (arg0) {
|
||||
const ret = getObject(arg0).next
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_next_ddb3312ca1c4e32a = function () {
|
||||
return handleError(function (arg0) {
|
||||
const ret = getObject(arg0).next()
|
||||
return addHeapObject(ret)
|
||||
}, arguments)
|
||||
}
|
||||
imports.wbg.__wbg_done_5c1f01fb660d73b5 = function (arg0) {
|
||||
const ret = getObject(arg0).done
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbg_value_1695675138684bd5 = function (arg0) {
|
||||
const ret = getObject(arg0).value
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_iterator_97f0c81209c6c35a = function () {
|
||||
const ret = Symbol.iterator
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_get_97b561fb56f034b5 = function () {
|
||||
return handleError(function (arg0, arg1) {
|
||||
const ret = Reflect.get(getObject(arg0), getObject(arg1))
|
||||
return addHeapObject(ret)
|
||||
}, arguments)
|
||||
}
|
||||
imports.wbg.__wbg_call_cb65541d95d71282 = function () {
|
||||
return handleError(function (arg0, arg1) {
|
||||
const ret = getObject(arg0).call(getObject(arg1))
|
||||
return addHeapObject(ret)
|
||||
}, arguments)
|
||||
}
|
||||
imports.wbg.__wbg_new_b51585de1b234aff = function () {
|
||||
const ret = new Object()
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_isArray_4c24b343cb13cfb1 = function (arg0) {
|
||||
const ret = Array.isArray(getObject(arg0))
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbg_instanceof_ArrayBuffer_39ac22089b74fddb = function (arg0) {
|
||||
let result
|
||||
try {
|
||||
result = getObject(arg0) instanceof ArrayBuffer
|
||||
} catch {
|
||||
result = false
|
||||
}
|
||||
const ret = result
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbg_isSafeInteger_bb8e18dd21c97288 = function (arg0) {
|
||||
const ret = Number.isSafeInteger(getObject(arg0))
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbg_entries_e51f29c7bba0c054 = function (arg0) {
|
||||
const ret = Object.entries(getObject(arg0))
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_buffer_085ec1f694018c4f = function (arg0) {
|
||||
const ret = getObject(arg0).buffer
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_new_8125e318e6245eed = function (arg0) {
|
||||
const ret = new Uint8Array(getObject(arg0))
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
imports.wbg.__wbg_set_5cf90238115182c3 = function (arg0, arg1, arg2) {
|
||||
getObject(arg0).set(getObject(arg1), arg2 >>> 0)
|
||||
}
|
||||
imports.wbg.__wbg_length_72e2208bbc0efc61 = function (arg0) {
|
||||
const ret = getObject(arg0).length
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbg_instanceof_Uint8Array_d8d9cb2b8e8ac1d4 = function (arg0) {
|
||||
let result
|
||||
try {
|
||||
result = getObject(arg0) instanceof Uint8Array
|
||||
} catch {
|
||||
result = false
|
||||
}
|
||||
const ret = result
|
||||
return ret
|
||||
}
|
||||
imports.wbg.__wbindgen_bigint_get_as_i64 = function (arg0, arg1) {
|
||||
const v = getObject(arg1)
|
||||
const ret = typeof v === 'bigint' ? v : undefined
|
||||
getBigInt64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? BigInt(0) : ret
|
||||
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret)
|
||||
}
|
||||
imports.wbg.__wbindgen_debug_string = function (arg0, arg1) {
|
||||
const ret = debugString(getObject(arg1))
|
||||
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc)
|
||||
const len1 = WASM_VECTOR_LEN
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len1
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr1
|
||||
}
|
||||
imports.wbg.__wbindgen_throw = function (arg0, arg1) {
|
||||
throw new Error(getStringFromWasm0(arg0, arg1))
|
||||
}
|
||||
imports.wbg.__wbindgen_memory = function () {
|
||||
const ret = wasm.memory
|
||||
return addHeapObject(ret)
|
||||
}
|
||||
|
||||
return imports
|
||||
}
|
||||
|
||||
function __wbg_init_memory(imports, maybe_memory) {}
|
||||
|
||||
function __wbg_finalize_init(instance, module) {
|
||||
wasm = instance.exports
|
||||
__wbg_init.__wbindgen_wasm_module = module
|
||||
cachedBigInt64Memory0 = null
|
||||
cachedFloat64Memory0 = null
|
||||
cachedInt32Memory0 = null
|
||||
cachedUint8Memory0 = null
|
||||
|
||||
return wasm
|
||||
}
|
||||
|
||||
function initSync(module) {
|
||||
if (wasm !== undefined) return wasm
|
||||
|
||||
const imports = __wbg_get_imports()
|
||||
|
||||
__wbg_init_memory(imports)
|
||||
|
||||
if (!(module instanceof WebAssembly.Module)) {
|
||||
module = new WebAssembly.Module(module)
|
||||
}
|
||||
|
||||
const instance = new WebAssembly.Instance(module, imports)
|
||||
|
||||
return __wbg_finalize_init(instance, module)
|
||||
}
|
||||
|
||||
async function __wbg_init(input) {
|
||||
if (wasm !== undefined) return wasm
|
||||
|
||||
if (typeof input === 'undefined') {
|
||||
input = new URL('index_bg.wasm', import.meta.url)
|
||||
}
|
||||
const imports = __wbg_get_imports()
|
||||
|
||||
if (
|
||||
typeof input === 'string' ||
|
||||
(typeof Request === 'function' && input instanceof Request) ||
|
||||
(typeof URL === 'function' && input instanceof URL)
|
||||
) {
|
||||
input = fetch(input)
|
||||
}
|
||||
|
||||
__wbg_init_memory(imports)
|
||||
|
||||
const { instance, module } = await __wbg_load(await input, imports)
|
||||
|
||||
return __wbg_finalize_init(instance, module)
|
||||
}
|
||||
|
||||
export { initSync }
|
||||
export default __wbg_init
|
BIN
src/utils/health_computer/index_bg.wasm
Normal file
BIN
src/utils/health_computer/index_bg.wasm
Normal file
Binary file not shown.
15
src/utils/health_computer/index_bg.wasm.d.ts
vendored
Normal file
15
src/utils/health_computer/index_bg.wasm.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export const memory: WebAssembly.Memory
|
||||
export function compute_health_js(a: number): number
|
||||
export function max_withdraw_estimate_js(a: number, b: number): number
|
||||
export function max_borrow_estimate_js(a: number, b: number): number
|
||||
export function allocate(a: number): number
|
||||
export function deallocate(a: number): void
|
||||
export function requires_stargate(): void
|
||||
export function requires_iterator(): void
|
||||
export function interface_version_8(): void
|
||||
export function __wbindgen_malloc(a: number, b: number): number
|
||||
export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number
|
||||
export function __wbindgen_free(a: number, b: number, c: number): void
|
||||
export function __wbindgen_exn_store(a: number): void
|
@ -1,21 +1,5 @@
|
||||
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'
|
||||
|
||||
export function resolvePositionResponses(responses: CreditManagerPosition[]): Account[] {
|
||||
return responses.map(resolvePositionResponse)
|
||||
}
|
||||
|
||||
export function resolvePositionResponse(response: CreditManagerPosition): Account {
|
||||
return {
|
||||
id: response.account_id,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveMarketResponses(responses: RedBankMarket[]): Market[] {
|
||||
return responses.map(resolveMarketResponse)
|
||||
}
|
||||
|
@ -2,40 +2,18 @@ import { IS_TESTNET } from 'constants/env'
|
||||
import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { Action } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import { getNetCollateralValue } from 'utils/accounts'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { getTokenPrice, getTokenValue } from 'utils/tokens'
|
||||
|
||||
export function getVaultsMetaData() {
|
||||
return IS_TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
|
||||
}
|
||||
|
||||
export function getVaultMetaData(address: string) {
|
||||
const vaults = IS_TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
|
||||
return vaults.find((vault) => vault.address === address)
|
||||
}
|
||||
|
||||
// This should be replaced when the calculation is made part of the Health Computer (MP-2877)
|
||||
export function calculateMaxBorrowAmounts(
|
||||
account: Account,
|
||||
marketAssets: Market[],
|
||||
prices: BNCoin[],
|
||||
denoms: string[],
|
||||
): BNCoin[] {
|
||||
const maxAmounts: BNCoin[] = []
|
||||
const collateralValue = getNetCollateralValue(account, marketAssets, prices)
|
||||
|
||||
for (const denom of denoms) {
|
||||
const borrowAsset = marketAssets.find((asset) => asset.denom === denom)
|
||||
const borrowAssetPrice = prices.find((price) => price.denom === denom)?.amount
|
||||
|
||||
if (!borrowAssetPrice || !borrowAsset) continue
|
||||
|
||||
const borrowValue = BN(1).minus(borrowAsset.maxLtv).multipliedBy(borrowAssetPrice)
|
||||
const amount = collateralValue.dividedBy(borrowValue).decimalPlaces(0)
|
||||
|
||||
maxAmounts.push(new BNCoin({ denom, amount: amount.toString() }))
|
||||
}
|
||||
|
||||
return maxAmounts
|
||||
}
|
||||
|
||||
export function getVaultDepositCoinsAndValue(
|
||||
vault: Vault,
|
||||
deposits: BNCoin[],
|
||||
@ -68,7 +46,7 @@ export function getVaultDepositCoinsAndValue(
|
||||
denom: vault.denoms.secondary,
|
||||
amount: secondaryDepositAmount.toString(),
|
||||
}),
|
||||
totalValue,
|
||||
totalValue: totalValue.integerValue(),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user