Scope Funding to actions, enable fund for USDC (and others) (#426)
* fix vault test and vaulttable pos value * fix vault test and vaulttable pos value updated * Scope lend for deposit to action only * fix build error * fix build error
This commit is contained in:
parent
19e06aa7d4
commit
46d4113d98
@ -22,13 +22,12 @@ describe('getVaultMetaData()', () => {
|
||||
expect(getVaultMetaData(testAddress)?.name).toBe(testVaultName)
|
||||
})
|
||||
|
||||
// TODO: Update the following test suite accordingly after new testnet vaults placed in constants
|
||||
// it('returns the TESTNET vault of given address WHEN environment configured to testnet', () => {
|
||||
// jest.spyOn(constants, 'IS_TESTNET', 'get').mockReturnValue(true)
|
||||
it('returns the TESTNET vault of given address WHEN environment configured to testnet', () => {
|
||||
jest.spyOn(constants, 'IS_TESTNET', 'get').mockReturnValue(true)
|
||||
|
||||
// const testAddress = 'osmo1q40xvrzpldwq5he4ftsf7zm2jf80tj373qaven38yqrvhex8r9rs8n94kv'
|
||||
// const testVaultName = 'OSMO-USDC.n'
|
||||
const testAddress = 'osmo1m45ap4rq4m2mfjkcqu9ks9mxmyx2hvx0cdca9sjmrg46q7lghzqqhxxup5'
|
||||
const testVaultName = 'OSMO-ATOM'
|
||||
|
||||
// expect(getVaultMetaData(testAddress)?.name).toBe(testVaultName)
|
||||
// })
|
||||
})
|
||||
expect(getVaultMetaData(testAddress)?.name).toBe(testVaultName)
|
||||
})
|
||||
})
|
@ -3,13 +3,15 @@ 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 { BN_ZERO } from 'constants/math'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { VaultStatus } from 'types/enums/vault'
|
||||
import {
|
||||
VaultPosition,
|
||||
VaultPositionAmount,
|
||||
} from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import { getCoinValue } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
|
||||
async function getUnlocksAtTimestamp(unlockingId: number, vaultAddress: string) {
|
||||
try {
|
||||
@ -130,8 +132,12 @@ async function getVaultValuesAndAmounts(
|
||||
secondary: BN(secondaryLpToken.amount),
|
||||
},
|
||||
values: {
|
||||
primary: BN(primaryLpToken.amount).multipliedBy(primaryPrice),
|
||||
secondary: BN(secondaryLpToken.amount).multipliedBy(secondaryPrice),
|
||||
primary: getCoinValue(new BNCoin(primaryLpToken), [
|
||||
BNCoin.fromDenomAndBigNumber(primaryLpToken.denom, primaryPrice),
|
||||
]),
|
||||
secondary: getCoinValue(new BNCoin(secondaryLpToken), [
|
||||
BNCoin.fromDenomAndBigNumber(secondaryLpToken.denom, secondaryPrice),
|
||||
]),
|
||||
},
|
||||
}
|
||||
} catch (ex) {
|
||||
@ -173,4 +179,4 @@ async function getDepositedVaults(accountId: string): Promise<DepositedVault[]>
|
||||
}
|
||||
}
|
||||
|
||||
export default getDepositedVaults
|
||||
export default getDepositedVaults
|
@ -40,6 +40,7 @@ export default function AccountFund() {
|
||||
const hasFundingAssets =
|
||||
fundingAssets.length > 0 && fundingAssets.every((a) => a.toCoin().amount !== '0')
|
||||
const { data: marketAssets } = useMarketAssets()
|
||||
const [isLending, toggleIsLending] = useToggle(false)
|
||||
|
||||
const baseBalance = useMemo(
|
||||
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
|
||||
@ -58,10 +59,11 @@ export default function AccountFund() {
|
||||
const result = await deposit({
|
||||
accountId,
|
||||
coins: fundingAssets,
|
||||
lend: isLending,
|
||||
})
|
||||
setIsFunding(false)
|
||||
if (result) useStore.setState({ focusComponent: null, walletAssetsModal: null })
|
||||
}, [fundingAssets, accountId, setIsFunding, deposit])
|
||||
}, [setIsFunding, accountId, deposit, fundingAssets, isLending])
|
||||
|
||||
const handleSelectAssetsClick = useCallback(() => {
|
||||
useStore.setState({
|
||||
@ -174,6 +176,8 @@ export default function AccountFund() {
|
||||
<SwitchAutoLend
|
||||
className='pt-4 mt-4 border border-transparent border-t-white/10'
|
||||
accountId={selectedAccountId}
|
||||
value={isLending}
|
||||
onChange={toggleIsLending}
|
||||
/>
|
||||
<Button
|
||||
className='w-full mt-4'
|
||||
@ -187,4 +191,4 @@ export default function AccountFund() {
|
||||
</Card>
|
||||
</FullOverlayContent>
|
||||
)
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ import { defaultFee } from 'utils/constants'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { isNumber } from 'utils/parsers'
|
||||
import { getPage, getRoute } from 'utils/route'
|
||||
|
||||
const menuClasses = 'absolute isolate flex w-full flex-wrap scrollbar-hide'
|
||||
const ACCOUNT_MENU_BUTTON_ID = 'account-menu-button'
|
||||
|
||||
@ -73,7 +74,16 @@ export default function AccountMenuContent(props: Props) {
|
||||
},
|
||||
})
|
||||
}
|
||||
}, [createAccount, navigate, pathname, address, setShowMenu, setIsCreating])
|
||||
}, [
|
||||
setShowMenu,
|
||||
setIsCreating,
|
||||
createAccount,
|
||||
navigate,
|
||||
pathname,
|
||||
address,
|
||||
lendAssets,
|
||||
enableAutoLendAccountId,
|
||||
])
|
||||
|
||||
const handleCreateAccountClick = useCallback(() => {
|
||||
setShowMenu(!showMenu)
|
||||
@ -154,4 +164,4 @@ export default function AccountMenuContent(props: Props) {
|
||||
)
|
||||
}
|
||||
|
||||
export { ACCOUNT_MENU_BUTTON_ID }
|
||||
export { ACCOUNT_MENU_BUTTON_ID }
|
@ -20,6 +20,7 @@ import { ChevronDown, SortAsc, SortDesc, SortNone } from 'components/Icons'
|
||||
import Loading from 'components/Loading'
|
||||
import Text from 'components/Text'
|
||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import { VAULT_DEPOSIT_BUFFER } from 'constants/vaults'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
@ -107,7 +108,7 @@ export const VaultTable = (props: Props) => {
|
||||
cell: ({ row }: { row: Row<DepositedVault | Vault> }) => {
|
||||
const vault = row.original as DepositedVault
|
||||
const positionValue = vault.values.primary.plus(vault.values.secondary)
|
||||
const coin = BNCoin.fromDenomAndBigNumber(baseCurrency.denom, positionValue)
|
||||
const coin = BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, positionValue)
|
||||
return <DisplayCurrency coin={coin} className='text-xs' />
|
||||
},
|
||||
},
|
||||
@ -229,7 +230,7 @@ export const VaultTable = (props: Props) => {
|
||||
},
|
||||
},
|
||||
]
|
||||
}, [baseCurrency.denom, props.data, props.isLoading])
|
||||
}, [props.data, props.isLoading])
|
||||
|
||||
const table = useReactTable({
|
||||
data: props.data,
|
||||
@ -305,4 +306,4 @@ export const VaultTable = (props: Props) => {
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
}
|
@ -251,4 +251,4 @@ function BorrowModal(props: Props) {
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ export default function FundAccount(props: Props) {
|
||||
const hasFundingAssets =
|
||||
fundingAssets.length > 0 && fundingAssets.every((a) => a.toCoin().amount !== '0')
|
||||
const { autoLendEnabledAccountIds } = useAutoLend()
|
||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(accountId)
|
||||
const [isLending, toggleIsLending] = useToggle(false)
|
||||
const { simulateDeposits } = useUpdatedAccount(account)
|
||||
const { data: marketAssets } = useMarketAssets()
|
||||
const baseBalance = useMemo(
|
||||
@ -59,10 +59,11 @@ export default function FundAccount(props: Props) {
|
||||
const result = await deposit({
|
||||
accountId,
|
||||
coins: fundingAssets,
|
||||
lend: isLending,
|
||||
})
|
||||
setIsFunding(false)
|
||||
if (result) useStore.setState({ fundAndWithdrawModal: null, walletAssetsModal: null })
|
||||
}, [fundingAssets, accountId, setIsFunding, deposit])
|
||||
}, [setIsFunding, accountId, deposit, fundingAssets, isLending])
|
||||
|
||||
const handleSelectAssetsClick = useCallback(() => {
|
||||
useStore.setState({
|
||||
@ -74,6 +75,10 @@ export default function FundAccount(props: Props) {
|
||||
})
|
||||
}, [selectedDenoms])
|
||||
|
||||
useEffect(() => {
|
||||
toggleIsLending(autoLendEnabledAccountIds.includes(accountId))
|
||||
}, [accountId, autoLendEnabledAccountIds, toggleIsLending])
|
||||
|
||||
useEffect(() => {
|
||||
const currentSelectedDenom = fundingAssets.map((asset) => asset.denom)
|
||||
|
||||
@ -101,8 +106,8 @@ export default function FundAccount(props: Props) {
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
simulateDeposits(isAutoLendEnabled ? 'lend' : 'deposit', fundingAssets)
|
||||
}, [isAutoLendEnabled, fundingAssets, simulateDeposits])
|
||||
simulateDeposits(isLending ? 'lend' : 'deposit', fundingAssets)
|
||||
}, [isLending, fundingAssets, simulateDeposits])
|
||||
|
||||
useEffect(() => {
|
||||
if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) {
|
||||
@ -165,6 +170,8 @@ export default function FundAccount(props: Props) {
|
||||
<SwitchAutoLend
|
||||
className='pt-4 mt-4 border border-transparent border-t-white/10'
|
||||
accountId={accountId}
|
||||
onChange={toggleIsLending}
|
||||
value={isLending}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
@ -177,4 +184,4 @@ export default function FundAccount(props: Props) {
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
@ -6,6 +6,8 @@ import useAutoLend from 'hooks/useAutoLend'
|
||||
interface Props {
|
||||
accountId: string
|
||||
className?: string
|
||||
onChange?: () => void
|
||||
value?: boolean
|
||||
}
|
||||
|
||||
export default function SwitchAutoLend(props: Props) {
|
||||
@ -13,15 +15,21 @@ export default function SwitchAutoLend(props: Props) {
|
||||
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLend()
|
||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(accountId)
|
||||
|
||||
function handleToggle() {
|
||||
if (props.onChange) return props.onChange()
|
||||
|
||||
toggleAutoLend(accountId)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames('w-full', className)}>
|
||||
<SwitchWithLabel
|
||||
name='isLending'
|
||||
label='Lend assets to earn yield'
|
||||
value={isAutoLendEnabled}
|
||||
onChange={() => toggleAutoLend(accountId)}
|
||||
value={props.value !== undefined ? props.value : isAutoLendEnabled}
|
||||
onChange={handleToggle}
|
||||
tooltip={`Fund your account and lend assets effortlessly! By lending, you'll earn attractive interest (APY) without impacting your LTV. It's a win-win situation - don't miss out on this easy opportunity to grow your holdings!`}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -21,7 +21,16 @@ export default function SwitchWithLabel(props: Props) {
|
||||
<Text className='mr-2 text-white/70' size='sm'>
|
||||
{props.label}
|
||||
</Text>
|
||||
{props.tooltip && <Tooltip type='info' content={<Text size='sm'>{props.tooltip}</Text>} />}
|
||||
{props.tooltip && (
|
||||
<Tooltip
|
||||
type='info'
|
||||
content={
|
||||
<Text size='sm' className='px-2 py-3'>
|
||||
{props.tooltip}
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Switch
|
||||
name={props.name}
|
||||
@ -31,4 +40,4 @@ export default function SwitchWithLabel(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -67,6 +67,7 @@ export const ASSETS: Asset[] = [
|
||||
isEnabled: !IS_TESTNET,
|
||||
isMarket: !IS_TESTNET,
|
||||
isDisplayCurrency: !IS_TESTNET,
|
||||
isAutoLendEnabled: true,
|
||||
poolId: 712,
|
||||
pythPriceFeedId: 'e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43',
|
||||
},
|
||||
@ -83,6 +84,7 @@ export const ASSETS: Asset[] = [
|
||||
isEnabled: !IS_TESTNET,
|
||||
isMarket: !IS_TESTNET,
|
||||
isDisplayCurrency: !IS_TESTNET,
|
||||
isAutoLendEnabled: true,
|
||||
poolId: 704,
|
||||
pythPriceFeedId: 'ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace',
|
||||
},
|
||||
@ -119,6 +121,7 @@ export const ASSETS: Asset[] = [
|
||||
isMarket: true,
|
||||
isDisplayCurrency: true,
|
||||
isStable: true,
|
||||
isAutoLendEnabled: true,
|
||||
poolId: 678,
|
||||
pythPriceFeedId: 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a',
|
||||
},
|
||||
@ -152,4 +155,4 @@ export const ASSETS: Asset[] = [
|
||||
hasOraclePrice: true,
|
||||
forceFetchPrice: true,
|
||||
},
|
||||
]
|
||||
]
|
@ -20,6 +20,7 @@ import { formatAmountWithSymbol } from 'utils/formatters'
|
||||
import getTokenOutFromSwapResponse from 'utils/getTokenOutFromSwapResponse'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
|
||||
function generateExecutionMessage(
|
||||
sender: string | undefined = '',
|
||||
contract: string,
|
||||
@ -209,7 +210,7 @@ export default function createBroadcastSlice(
|
||||
|
||||
return { estimateFee, execute }
|
||||
},
|
||||
deposit: async (options: { accountId: string; coins: BNCoin[] }) => {
|
||||
deposit: async (options: { accountId: string; coins: BNCoin[]; lend: boolean }) => {
|
||||
const msg: CreditManagerExecuteMsg = {
|
||||
update_credit_account: {
|
||||
account_id: options.accountId,
|
||||
@ -219,11 +220,11 @@ export default function createBroadcastSlice(
|
||||
},
|
||||
}
|
||||
|
||||
if (checkAutoLendEnabled(options.accountId)) {
|
||||
if (options.lend) {
|
||||
msg.update_credit_account.actions.push(
|
||||
...options.coins
|
||||
.filter((coin) => getAssetByDenom(coin.denom)?.isAutoLendEnabled)
|
||||
.map((coin) => ({ lend: coin.toActionCoin(true) })),
|
||||
.map((coin) => ({ lend: coin.toActionCoin(options.lend) })),
|
||||
)
|
||||
}
|
||||
|
||||
@ -238,7 +239,9 @@ export default function createBroadcastSlice(
|
||||
.join(' and ')
|
||||
handleResponseMessages(
|
||||
response,
|
||||
`Deposited ${depositString} to Credit Credit Account ${options.accountId}`,
|
||||
`Deposited ${options.lend ? 'and lent ' : ''}${depositString} to Credit Credit Account ${
|
||||
options.accountId
|
||||
}`,
|
||||
)
|
||||
return !!response.result
|
||||
},
|
||||
@ -524,4 +527,4 @@ export default function createBroadcastSlice(
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
4
src/types/interfaces/store/broadcast.d.ts
vendored
4
src/types/interfaces/store/broadcast.d.ts
vendored
@ -20,7 +20,7 @@ interface BroadcastSlice {
|
||||
claimRewards: (options: { accountId: string }) => ExecutableTx
|
||||
createAccount: () => Promise<string | null>
|
||||
deleteAccount: (options: { accountId: string; lends: BNCoin[] }) => Promise<boolean>
|
||||
deposit: (options: { accountId: string; coins: BNCoin[] }) => Promise<boolean>
|
||||
deposit: (options: { accountId: string; coins: BNCoin[]; lend: boolean }) => Promise<boolean>
|
||||
depositIntoVault: (options: { accountId: string; actions: Action[] }) => Promise<boolean>
|
||||
executeMsg: (options: { messages: MsgExecuteContract[] }) => Promise<BroadcastResult>
|
||||
lend: (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => Promise<boolean>
|
||||
@ -52,4 +52,4 @@ interface BroadcastSlice {
|
||||
borrow: BNCoin[]
|
||||
reclaims: ActionCoin[]
|
||||
}) => Promise<boolean>
|
||||
}
|
||||
}
|
@ -16,12 +16,7 @@ export const getTokenIcon = (denom: string, marketAssets: Asset[]) =>
|
||||
export const getTokenInfo = (denom: string, marketAssets: Asset[]) =>
|
||||
marketAssets.find((asset) => asset.denom.toLowerCase() === denom.toLowerCase()) || getBaseAsset()
|
||||
|
||||
export function getTokenValue(coin: BNCoin, prices: BNCoin[]): BigNumber {
|
||||
const price = prices.find((price) => price.denom === coin.denom)?.amount || '0'
|
||||
return BN(price).multipliedBy(coin.amount).decimalPlaces(0)
|
||||
}
|
||||
|
||||
export function getTokenPrice(denom: string, prices: BNCoin[]): BigNumber {
|
||||
const price = prices.find((price) => price.denom === denom)?.amount || '0'
|
||||
return BN(price)
|
||||
}
|
||||
}
|
@ -5,9 +5,9 @@ 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 { getAssetByDenom } from 'utils/assets'
|
||||
import { getTokenPrice, getTokenValue } from 'utils/tokens'
|
||||
|
||||
import { getValueFromBNCoins, mergeBNCoinArrays } from './helpers'
|
||||
import { getCoinValue } from 'utils/formatters'
|
||||
import { getValueFromBNCoins, mergeBNCoinArrays } from 'utils/helpers'
|
||||
import { getTokenPrice } from 'utils/tokens'
|
||||
|
||||
export function getVaultsMetaData() {
|
||||
return IS_TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
|
||||
@ -88,7 +88,7 @@ export function getVaultSwapActions(
|
||||
)
|
||||
|
||||
primaryCoins.forEach((bnCoin) => {
|
||||
let value = getTokenValue(bnCoin, prices)
|
||||
let value = getCoinValue(bnCoin, prices)
|
||||
if (value.isLessThanOrEqualTo(primaryLeftoverValue)) {
|
||||
primaryLeftoverValue = primaryLeftoverValue.minus(value)
|
||||
} else {
|
||||
@ -99,7 +99,7 @@ export function getVaultSwapActions(
|
||||
})
|
||||
|
||||
secondaryCoins.forEach((bnCoin) => {
|
||||
let value = getTokenValue(bnCoin, prices)
|
||||
let value = getCoinValue(bnCoin, prices)
|
||||
if (value.isLessThanOrEqualTo(secondaryLeftoverValue)) {
|
||||
secondaryLeftoverValue = secondaryLeftoverValue.minus(value)
|
||||
} else {
|
||||
@ -110,7 +110,7 @@ export function getVaultSwapActions(
|
||||
})
|
||||
|
||||
otherCoins.forEach((bnCoin) => {
|
||||
let value = getTokenValue(bnCoin, prices)
|
||||
let value = getCoinValue(bnCoin, prices)
|
||||
let amount = bnCoin.amount
|
||||
|
||||
if (primaryLeftoverValue.isGreaterThan(0)) {
|
||||
@ -177,4 +177,4 @@ function getSwapAction(denomIn: string, denomOut: string, amount: BigNumber, sli
|
||||
slippage: slippage.toString(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user