173 lines
5.1 KiB
TypeScript
173 lines
5.1 KiB
TypeScript
import { IS_TESTNET } from 'constants/env'
|
|
import { BN_ZERO } from 'constants/math'
|
|
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 { 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)
|
|
}
|
|
|
|
export function getVaultDepositCoinsAndValue(
|
|
vault: Vault,
|
|
deposits: BNCoin[],
|
|
borrowings: BNCoin[],
|
|
prices: BNCoin[],
|
|
) {
|
|
const totalValue = [...deposits, ...borrowings].reduce((prev, bnCoin) => {
|
|
const price = prices.find((coin) => coin.denom === bnCoin.denom)?.amount
|
|
if (!price) return prev
|
|
|
|
return prev.plus(bnCoin.amount.multipliedBy(price))
|
|
}, BN_ZERO)
|
|
|
|
const halfValue = totalValue.dividedBy(2)
|
|
|
|
const primaryDepositAmount = halfValue
|
|
.dividedBy(getTokenPrice(vault.denoms.primary, prices))
|
|
.integerValue()
|
|
|
|
const secondaryDepositAmount = halfValue
|
|
.dividedBy(getTokenPrice(vault.denoms.secondary, prices))
|
|
.integerValue()
|
|
|
|
return {
|
|
primaryCoin: new BNCoin({
|
|
denom: vault.denoms.primary,
|
|
amount: primaryDepositAmount.toString(),
|
|
}),
|
|
secondaryCoin: new BNCoin({
|
|
denom: vault.denoms.secondary,
|
|
amount: secondaryDepositAmount.toString(),
|
|
}),
|
|
totalValue: totalValue.integerValue(),
|
|
}
|
|
}
|
|
|
|
export function getVaultSwapActions(
|
|
vault: Vault,
|
|
deposits: BNCoin[],
|
|
borrowings: BNCoin[],
|
|
prices: BNCoin[],
|
|
slippage: number,
|
|
totalValue: BigNumber,
|
|
): Action[] {
|
|
const swapActions: Action[] = []
|
|
const coins = [...deposits, ...borrowings]
|
|
|
|
let primaryLeftoverValue = totalValue.dividedBy(2).integerValue()
|
|
let secondaryLeftoverValue = totalValue.dividedBy(2).integerValue()
|
|
|
|
const [primaryCoins, secondaryCoins, otherCoins] = coins.reduce(
|
|
(prev, bnCoin) => {
|
|
switch (bnCoin.denom) {
|
|
case vault.denoms.primary:
|
|
prev[0].push(bnCoin)
|
|
break
|
|
case vault.denoms.secondary:
|
|
prev[1].push(bnCoin)
|
|
break
|
|
default:
|
|
prev[2].push(bnCoin)
|
|
}
|
|
return prev
|
|
},
|
|
[[], [], []] as [BNCoin[], BNCoin[], BNCoin[]],
|
|
)
|
|
|
|
primaryCoins.forEach((bnCoin) => {
|
|
let value = getTokenValue(bnCoin, prices)
|
|
if (value.isLessThanOrEqualTo(primaryLeftoverValue)) {
|
|
primaryLeftoverValue = primaryLeftoverValue.minus(value)
|
|
} else {
|
|
value = value.minus(primaryLeftoverValue)
|
|
primaryLeftoverValue = primaryLeftoverValue.minus(primaryLeftoverValue)
|
|
otherCoins.push(new BNCoin({ denom: bnCoin.denom, amount: value.toString() }))
|
|
}
|
|
})
|
|
|
|
secondaryCoins.forEach((bnCoin) => {
|
|
let value = getTokenValue(bnCoin, prices)
|
|
if (value.isLessThanOrEqualTo(secondaryLeftoverValue)) {
|
|
secondaryLeftoverValue = secondaryLeftoverValue.minus(value)
|
|
} else {
|
|
value = value.minus(secondaryLeftoverValue)
|
|
secondaryLeftoverValue = secondaryLeftoverValue.minus(secondaryLeftoverValue)
|
|
otherCoins.push(new BNCoin({ denom: bnCoin.denom, amount: value.toString() }))
|
|
}
|
|
})
|
|
|
|
otherCoins.forEach((bnCoin) => {
|
|
let value = getTokenValue(bnCoin, prices)
|
|
let amount = bnCoin.amount
|
|
|
|
if (primaryLeftoverValue.isGreaterThan(0)) {
|
|
const swapValue = value.isLessThan(primaryLeftoverValue) ? value : primaryLeftoverValue
|
|
const swapAmount = swapValue
|
|
.dividedBy(prices.find((coin) => coin.denom === bnCoin.denom)?.amount || 1)
|
|
.integerValue()
|
|
value = value.minus(swapValue)
|
|
amount = amount.minus(swapAmount)
|
|
primaryLeftoverValue = primaryLeftoverValue.minus(swapValue)
|
|
swapActions.push(getSwapAction(bnCoin.denom, vault.denoms.primary, swapAmount, slippage))
|
|
}
|
|
|
|
if (secondaryLeftoverValue.isGreaterThan(0)) {
|
|
secondaryLeftoverValue = secondaryLeftoverValue.minus(value)
|
|
swapActions.push(getSwapAction(bnCoin.denom, vault.denoms.secondary, amount, slippage))
|
|
}
|
|
})
|
|
|
|
return swapActions
|
|
}
|
|
|
|
export function getEnterVaultActions(
|
|
vault: Vault,
|
|
primaryCoin: BNCoin,
|
|
secondaryCoin: BNCoin,
|
|
minLpToReceive: BigNumber,
|
|
): Action[] {
|
|
return [
|
|
{
|
|
provide_liquidity: {
|
|
// Smart Contact demands that secondary coin is first
|
|
coins_in: [secondaryCoin.toActionCoin(), primaryCoin.toActionCoin()],
|
|
lp_token_out: vault.denoms.lp,
|
|
minimum_receive: minLpToReceive.toString(),
|
|
},
|
|
},
|
|
{
|
|
enter_vault: {
|
|
coin: {
|
|
denom: vault.denoms.lp,
|
|
amount: 'account_balance',
|
|
},
|
|
vault: {
|
|
address: vault.address,
|
|
},
|
|
},
|
|
},
|
|
]
|
|
}
|
|
|
|
function getSwapAction(denomIn: string, denomOut: string, amount: BigNumber, slippage: number) {
|
|
return {
|
|
swap_exact_in: {
|
|
coin_in: {
|
|
denom: denomIn,
|
|
amount: {
|
|
exact: amount.toString(),
|
|
},
|
|
},
|
|
denom_out: denomOut,
|
|
slippage: slippage.toString(),
|
|
},
|
|
}
|
|
}
|