mars-v2-frontend/src/api/vaults/getDepositedVaults.ts
2023-07-14 14:49:33 +03:00

176 lines
5.1 KiB
TypeScript

import moment from 'moment'
import { getClient, getCreditManagerQueryClient, getVaultQueryClient } from 'api/cosmwasm-client'
import getPrice from 'api/prices/getPrice'
import getVaults from 'api/vaults/getVaults'
import { VaultStatus } from 'types/enums/vault'
import {
VaultPosition,
VaultPositionAmount,
} from 'types/generated/mars-credit-manager/MarsCreditManager.types'
import { BN } from 'utils/helpers'
async function getUnlocksAtTimestamp(unlockingId: number, vaultAddress: string) {
try {
const client = await getClient()
const vaultExtension = (await client.queryContractSmart(vaultAddress, {
vault_extension: { lockup: { unlocking_position: { lockup_id: unlockingId } } },
})) as VaultExtensionResponse
return Number(vaultExtension.release_at.at_time) / 1e6
} catch (ex) {
throw ex
}
}
async function getVaultPositionStatusAndUnlockIdAndUnlockTime(
vaultPosition: VaultPosition,
): Promise<[VaultStatus, number | undefined, number | undefined]> {
const amount = vaultPosition.amount
if (VaultStatus.UNLOCKED in amount) return [VaultStatus.UNLOCKED, undefined, undefined]
if (amount.locking.unlocking.length) {
const unlockId = amount.locking.unlocking[0].id
const unlocksAtTimestamp = await getUnlocksAtTimestamp(unlockId, vaultPosition.vault.address)
if (moment(unlocksAtTimestamp).isBefore(new Date())) {
return [VaultStatus.UNLOCKED, unlockId, unlocksAtTimestamp]
}
return [VaultStatus.UNLOCKING, unlockId, unlocksAtTimestamp]
} else {
return [VaultStatus.ACTIVE, undefined, undefined]
}
}
function flatVaultPositionAmount(
vaultPositionAmount: VaultPositionAmount,
): VaultPositionFlatAmounts {
const amounts = {
locked: BN(0),
unlocking: BN(0),
unlocked: BN(0),
}
if ('locking' in vaultPositionAmount) {
const { locked, unlocking } = vaultPositionAmount.locking
amounts.locked = BN(locked)
amounts.unlocking = BN(unlocking[0]?.coin.amount ?? '0')
} else if ('unlocked' in vaultPositionAmount) {
amounts.unlocked = BN(vaultPositionAmount.unlocked)
}
return amounts
}
async function getLpTokensForVaultPosition(
vault: Vault,
vaultPosition: VaultPosition,
): Promise<Coin[]> {
try {
const vaultQueryClient = await getVaultQueryClient(vault.address)
const creditManagerQueryClient = await getCreditManagerQueryClient()
const amounts = flatVaultPositionAmount(vaultPosition.amount)
const totalAmount = BN(amounts.locked)
.plus(BN(amounts.unlocked))
.plus(BN(amounts.unlocking))
.toString()
const lpAmount = await vaultQueryClient.previewRedeem({
amount: totalAmount,
})
const lpTokens = await creditManagerQueryClient.estimateWithdrawLiquidity({
lpToken: {
amount: lpAmount,
denom: vault.denoms.lp,
},
})
const primaryLpToken = lpTokens.find((t) => t.denom === vault.denoms.primary) ?? {
amount: '0',
denom: vault.denoms.primary,
}
const secondaryLpToken = lpTokens.find((t) => t.denom === vault.denoms.secondary) ?? {
amount: '0',
denom: vault.denoms.secondary,
}
return [primaryLpToken, secondaryLpToken]
} catch (ex) {
throw ex
}
}
async function getVaultValuesAndAmounts(
vault: Vault,
vaultPosition: VaultPosition,
): Promise<VaultValuesAndAmounts> {
try {
const pricesQueries = Promise.all([
getPrice(vault.denoms.primary),
getPrice(vault.denoms.secondary),
])
const lpTokensQuery = getLpTokensForVaultPosition(vault, vaultPosition)
const amounts = flatVaultPositionAmount(vaultPosition.amount)
const [[primaryLpToken, secondaryLpToken], [primaryAsset, secondaryAsset]] = await Promise.all([
lpTokensQuery,
pricesQueries,
])
return {
amounts: {
...amounts,
primary: BN(primaryLpToken.amount),
secondary: BN(secondaryLpToken.amount),
},
values: {
primary: BN(primaryLpToken.amount).multipliedBy(primaryAsset),
secondary: BN(secondaryLpToken.amount).multipliedBy(secondaryAsset),
},
}
} catch (ex) {
throw ex
}
}
async function getDepositedVaults(accountId: string): Promise<DepositedVault[]> {
try {
const creditManagerQueryClient = await getCreditManagerQueryClient()
const positionsQuery = creditManagerQueryClient.positions({ accountId })
const [positions, allVaults] = await Promise.all([positionsQuery, getVaults()])
const depositedVaults = positions.vaults.map(async (vaultPosition) => {
const vault = allVaults.find((v) => v.address === vaultPosition.vault.address)
if (!vault) {
throw 'Could not find the deposited vault among all vaults'
}
const [[status, unlockId, unlocksAt], valuesAndAmounts] = await Promise.all([
getVaultPositionStatusAndUnlockIdAndUnlockTime(vaultPosition),
getVaultValuesAndAmounts(vault, vaultPosition),
])
return {
...vault,
status,
unlockId,
unlocksAt,
...valuesAndAmounts,
}
})
return await Promise.all(depositedVaults)
} catch (ex) {
throw ex
}
}
export default getDepositedVaults