Added chain agnostic v2 (#710)
* update assets config and chains
* make clients dynamic
* feat: formatted ChainSelect
* fix infinite rerender on trade page
* feat: added NTRN icon
* fix: fixed ChainInfoID
* fix: fixed autoLendEnabled for NTRN
* fix: fixed the navigation and dependencies
* fix: fixed the pricefeed id
* fix: fixed the header menu
* fix: fixed the trading charts
* fix: fixed the healthbars
* fix: fixed naming of pion-1
* feast: updated xdefi image
* env: updated contracts
* make localStorage chain agnostic
* fix: made the selected chain persistant
* fix: fixed the wallet providers
* fix: updated auto connect
* fix: fixed auto connecting
* fix: added ChainSelect to focusMode
* store raw strings in localstorage
* 🔥 remnove tests
* update caching keys + disconnect wallet on change chain
* fix: fixed the chain select
* env: bumped version
---------
Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
This commit is contained in:
parent
a4cdede670
commit
fb830c08cc
44
.env.example
44
.env.example
@ -1,37 +1,11 @@
|
|||||||
# DEVNET #
|
NEXT_PUBLIC_OSMOSIS1_RPC='https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-rpc-front/'
|
||||||
NEXT_PUBLIC_NETWORK=devnet
|
NEXT_PUBLIC_OSMOSIS1_REST='https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-lcd-front/'
|
||||||
NEXT_PUBLIC_CHAIN_ID=devnet
|
NEXT_PUBLIC_OSMOSIS_DEVNET_RPC='https://rpc.devnet.osmosis.zone/'
|
||||||
NEXT_PUBLIC_RPC=https://rpc.devnet.osmosis.zone/
|
NEXT_PUBLIC_OSMOSIS_DEVNET_REST='https://lcd.devnet.osmosis.zone/'
|
||||||
NEXT_PUBLIC_GQL=https://devnet-osmosis-gql.marsprotocol.io/graphql
|
NEXT_PUBLIC_PION1_RPC='https://rpc-palvus.pion-1.ntrn.tech/'
|
||||||
NEXT_PUBLIC_REST=https://lcd.devnet.osmosis.zone/
|
NEXT_PUBLIC_PION1_REST='https://rest-palvus.pion-1.ntrn.tech/'
|
||||||
|
|
||||||
|
|
||||||
# MAINNET #
|
|
||||||
NEXT_PUBLIC_NETWORK=mainnet
|
|
||||||
NEXT_PUBLIC_CHAIN_ID=osmosis-1
|
|
||||||
NEXT_PUBLIC_RPC=https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-rpc-front/
|
|
||||||
NEXT_PUBLIC_GQL=https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-hive-front/graphql
|
|
||||||
NEXT_PUBLIC_REST=https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-lcd-front/
|
|
||||||
|
|
||||||
|
|
||||||
# COMMON #
|
|
||||||
NEXT_PUBLIC_SWAP=https://app.osmosis.zone
|
|
||||||
NEXT_PUBLIC_VAULT_APR=https://api.marsprotocol.io/v1/vaults/osmosis
|
|
||||||
NEXT_PUBLIC_ACCOUNT_NFT=osmo1450hrg6dv2l58c0rvdwx8ec2a0r6dd50hn4frk370tpvqjhy8khqw7sw09
|
|
||||||
NEXT_PUBLIC_ORACLE=osmo1mhznfr60vjdp2gejhyv2gax9nvyyzhd3z0qcwseyetkfustjauzqycsy2g
|
|
||||||
NEXT_PUBLIC_RED_BANK=osmo1c3ljch9dfw5kf52nfwpxd2zmj2ese7agnx0p9tenkrryasrle5sqf3ftpg
|
|
||||||
NEXT_PUBLIC_CREDIT_MANAGER=osmo1f2m24wktq0sw3c0lexlg7fv4kngwyttvzws3a3r3al9ld2s2pvds87jqvf
|
|
||||||
NEXT_PUBLIC_INCENTIVES=osmo1nkahswfr8shg8rlxqwup0vgahp0dk4x8w6tkv3rra8rratnut36sk22vrm
|
|
||||||
NEXT_PUBLIC_SWAPPER=osmo1wee0z8c7tcawyl647eapqs4a88q8jpa7ddy6nn2nrs7t47p2zhxswetwla
|
|
||||||
NEXT_PUBLIC_PYTH=osmo13ge29x4e2s63a8ytz2px8gurtyznmue4a69n5275692v3qn3ks8q7cwck7
|
|
||||||
NEXT_PUBLIC_ZAPPER=osmo17qwvc70pzc9mudr8t02t3pl74hhqsgwnskl734p4hug3s8mkerdqzduf7c
|
|
||||||
NEXT_PUBLIC_PARAMS=osmo1nlmdxt9ctql2jr47qd4fpgzg84cjswxyw6q99u4y4u4q6c2f5ksq7ysent
|
|
||||||
NEXT_PUBLIC_PYTH_ENDPOINT=https://hermes.pyth.network/api
|
|
||||||
NEXT_PUBLIC_MAINNET_REST=https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-rpc-front/
|
|
||||||
NEXT_PUBLIC_CANDLES_ENDPOINT_THE_GRAPH=https://osmosis-candles.marsprotocol.io/
|
|
||||||
NEXT_PUBLIC_CANDLES_ENDPOINT_PYTH=https://benchmarks.pyth.network
|
|
||||||
NEXT_PUBLIC_WALLET_CONNECT_ID=d93fdffb159bae5ec87d8fee4cdbb045
|
NEXT_PUBLIC_WALLET_CONNECT_ID=d93fdffb159bae5ec87d8fee4cdbb045
|
||||||
CHARTING_LIBRARY_REPOSITORY=github.com/tradingview/charting_library
|
CHARTING_LIBRARY_USERNAME="git_username"
|
||||||
CHARTING_LIBRARY_ACCESS_TOKEN=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
|
CHARTING_LIBRARY_ACCESS_TOKEN="access_token"
|
||||||
CHARTING_LIBRARY_USERNAME=mars-git-demo
|
CHARTING_LIBRARY_REPOSITORY="github.com/tradingview/charting_library/"
|
||||||
NEXT_PUBLIC_STRIDE_APRS=https://edge.stride.zone/api/stake-stats
|
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
src: '/img.jpg',
|
|
||||||
height: 24,
|
|
||||||
width: 24,
|
|
||||||
blurDataURL: 'data:image/png;base64,imagedata',
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
jest.mock('react-helmet-async', () => {
|
|
||||||
const React = require('react')
|
|
||||||
const plugin = jest.requireActual('react-helmet-async')
|
|
||||||
const mockHelmet = ({ children, ...props }) =>
|
|
||||||
React.createElement(
|
|
||||||
'div',
|
|
||||||
{
|
|
||||||
...props,
|
|
||||||
className: 'mock-helmet',
|
|
||||||
},
|
|
||||||
children,
|
|
||||||
)
|
|
||||||
return {
|
|
||||||
...plugin,
|
|
||||||
Helmet: jest.fn().mockImplementation(mockHelmet),
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,23 +0,0 @@
|
|||||||
jest.mock('store', () => {
|
|
||||||
let state = {}
|
|
||||||
|
|
||||||
const mockUseStore = (selectorFn) => {
|
|
||||||
return selectorFn(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
mockUseStore.setState = (newState) => {
|
|
||||||
state = {
|
|
||||||
...state,
|
|
||||||
...newState,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mockUseStore.clearState = () => {
|
|
||||||
state = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
__esModule: true,
|
|
||||||
default: mockUseStore,
|
|
||||||
}
|
|
||||||
})
|
|
@ -1 +0,0 @@
|
|||||||
module.exports = {}
|
|
@ -1,7 +0,0 @@
|
|||||||
/* eslint-disable react/display-name */
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
const SvgrMock = React.forwardRef((props, ref) => <svg ref={ref} {...props} />)
|
|
||||||
|
|
||||||
export const ReactComponent = SvgrMock
|
|
||||||
export default SvgrMock
|
|
@ -1,14 +0,0 @@
|
|||||||
import { render } from '@testing-library/react'
|
|
||||||
|
|
||||||
import Footer from 'components/Footer'
|
|
||||||
|
|
||||||
import packageJSON from '../package.json'
|
|
||||||
|
|
||||||
describe('<Footer />', () => {
|
|
||||||
it('should render package version correctly', () => {
|
|
||||||
const { getByText, container } = render(<Footer />)
|
|
||||||
const versionText = getByText(`v${packageJSON.version}`)
|
|
||||||
|
|
||||||
expect(versionText).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,67 +0,0 @@
|
|||||||
import { render, screen } from '@testing-library/react'
|
|
||||||
|
|
||||||
import AccountDetails from 'components/Account/AccountDetails'
|
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
|
||||||
import useStore from 'store'
|
|
||||||
|
|
||||||
jest.mock('react-router', () => ({
|
|
||||||
...(jest.requireActual('react-router') as {}),
|
|
||||||
useLocation: jest.fn().mockImplementation(() => {
|
|
||||||
return { pathname: '/testroute' }
|
|
||||||
}),
|
|
||||||
}))
|
|
||||||
jest.mock('hooks/useCurrentAccount', () => jest.fn(() => null))
|
|
||||||
jest.mock('hooks/useHealthComputer', () =>
|
|
||||||
jest.fn(() => ({
|
|
||||||
health: 0,
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
// AccountBalancesTable component has wallet provider dependency, so we mock it
|
|
||||||
jest.mock('components/Account/AccountBalancesTable', () => jest.fn(() => null))
|
|
||||||
|
|
||||||
const mockedUseCurrentAccount = useCurrentAccount as jest.Mock
|
|
||||||
const mockedAccounts: Account[] = [
|
|
||||||
{ id: '1', deposits: [], lends: [], debts: [], vaults: [], kind: 'default' },
|
|
||||||
{ id: '2', deposits: [], lends: [], debts: [], vaults: [], kind: 'default' },
|
|
||||||
]
|
|
||||||
jest.mock('hooks/useAccountId', () => jest.fn(() => '1'))
|
|
||||||
jest.mock('hooks/useAccounts', () =>
|
|
||||||
jest.fn(() => ({
|
|
||||||
data: mockedAccounts,
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
jest.mock('hooks/useAccountIds', () =>
|
|
||||||
jest.fn(() => ({
|
|
||||||
data: ['1', '2'],
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
jest.mock('hooks/useCurrentAccount', () => jest.fn(() => mockedAccounts[0]))
|
|
||||||
|
|
||||||
describe('<AccountDetails />', () => {
|
|
||||||
beforeAll(() => {
|
|
||||||
useStore.setState({
|
|
||||||
address: 'walletAddress',
|
|
||||||
accounts: mockedAccounts,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
useStore.clearState()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('renders account details WHEN account is selected', () => {
|
|
||||||
mockedUseCurrentAccount.mockReturnValue(mockedAccounts)
|
|
||||||
render(<AccountDetails />)
|
|
||||||
|
|
||||||
const container = screen.queryByTestId('account-details')
|
|
||||||
expect(container).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('does not render WHEN account is NOT selected', () => {
|
|
||||||
mockedUseCurrentAccount.mockReturnValue(null)
|
|
||||||
render(<AccountDetails />)
|
|
||||||
|
|
||||||
const container = screen.queryByTestId('account-details')
|
|
||||||
expect(container).not.toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,157 +0,0 @@
|
|||||||
import { cleanup, render } from '@testing-library/react'
|
|
||||||
|
|
||||||
import Button from 'components/Button'
|
|
||||||
import {
|
|
||||||
buttonColorClasses,
|
|
||||||
buttonSizeClasses,
|
|
||||||
buttonVariantClasses,
|
|
||||||
focusClasses,
|
|
||||||
} from 'components/Button/constants'
|
|
||||||
import { parseMockComponentProps } from 'utils/testing'
|
|
||||||
|
|
||||||
jest.mock('components/CircularProgress', () => {
|
|
||||||
return {
|
|
||||||
CircularProgress: (props: any) =>
|
|
||||||
require('utils/testing').createMockComponent('circular-progress-component', props),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('<Button />', () => {
|
|
||||||
afterAll(() => {
|
|
||||||
jest.unmock('components/CircularProgress')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render', () => {
|
|
||||||
const { container } = render(<Button />)
|
|
||||||
expect(container).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render `children` when its passed', () => {
|
|
||||||
const children = <span data-testid='test-id'>Hello World!</span>
|
|
||||||
const { getByTestId } = render(<Button>{children}</Button>)
|
|
||||||
|
|
||||||
expect(getByTestId('test-id')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `className` prop correctly', () => {
|
|
||||||
const testClass = 'test-class'
|
|
||||||
const { container } = render(<Button className={testClass} />)
|
|
||||||
|
|
||||||
expect(container.querySelector('button')).toHaveClass(testClass)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `color` prop correctly', () => {
|
|
||||||
const colors = Object.keys(buttonColorClasses) as [keyof typeof buttonColorClasses]
|
|
||||||
|
|
||||||
colors.forEach((color) => {
|
|
||||||
const { container } = render(<Button color={color} />)
|
|
||||||
|
|
||||||
expect(container.querySelector('button')).toHaveClass(buttonColorClasses[color])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `disabled=true` prop correctly', () => {
|
|
||||||
const testFunction = jest.fn()
|
|
||||||
const { container } = render(<Button disabled={true} onClick={testFunction} />)
|
|
||||||
const button = container.querySelector('button')
|
|
||||||
|
|
||||||
button?.click()
|
|
||||||
|
|
||||||
expect(button).toHaveClass('pointer-events-none')
|
|
||||||
expect(testFunction).not.toBeCalled()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `disabled=false` prop correctly', () => {
|
|
||||||
const testFunction = jest.fn()
|
|
||||||
const { container } = render(<Button disabled={false} onClick={testFunction} />)
|
|
||||||
const button = container.querySelector('button')
|
|
||||||
|
|
||||||
button?.click()
|
|
||||||
|
|
||||||
expect(button).not.toHaveClass('pointer-events-none')
|
|
||||||
expect(testFunction).toBeCalled()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should show progress indicator when `showProgressIndicator=true`', () => {
|
|
||||||
const { getByTestId } = render(<Button showProgressIndicator={true} />)
|
|
||||||
const circularProgressComponent = getByTestId('circular-progress-component')
|
|
||||||
|
|
||||||
expect(circularProgressComponent).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should set correct values for progress indicator size', () => {
|
|
||||||
const sizeValues = { xs: 8, sm: 10, md: 12, lg: 18 }
|
|
||||||
|
|
||||||
Object.entries(sizeValues).forEach(([size, value]) => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<Button showProgressIndicator={true} size={size as keyof typeof buttonSizeClasses} />,
|
|
||||||
)
|
|
||||||
const circularProgressComponent = getByTestId('circular-progress-component')
|
|
||||||
const sizeProp = parseMockComponentProps(circularProgressComponent).size
|
|
||||||
|
|
||||||
expect(sizeProp).toBe(value)
|
|
||||||
cleanup()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `size` prop correctly', () => {
|
|
||||||
const sizes = Object.keys(buttonSizeClasses) as [keyof typeof buttonSizeClasses]
|
|
||||||
|
|
||||||
sizes.forEach((size) => {
|
|
||||||
const { container } = render(<Button size={size} />)
|
|
||||||
|
|
||||||
expect(container.querySelector('button')).toHaveClass(buttonSizeClasses[size])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should show `text` when its passed', () => {
|
|
||||||
const text = 'Hello!'
|
|
||||||
const { getByText } = render(<Button text={text} />)
|
|
||||||
|
|
||||||
expect(getByText(text)).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `variant` prop correctly', () => {
|
|
||||||
const variants = Object.keys(buttonVariantClasses) as [keyof typeof buttonVariantClasses]
|
|
||||||
|
|
||||||
variants.forEach((variant) => {
|
|
||||||
const { container } = render(<Button variant={variant} />)
|
|
||||||
|
|
||||||
expect(container.querySelector('button')).toHaveClass(buttonVariantClasses[variant])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should show left icon when `leftIcon` prop is passed', () => {
|
|
||||||
const icon = <span data-testid='left-icon'>this is the left icon</span>
|
|
||||||
const { getByTestId } = render(<Button leftIcon={icon} />)
|
|
||||||
|
|
||||||
expect(getByTestId('left-icon')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should show right icon when `rightIcon` prop is passed', () => {
|
|
||||||
const icon = <span data-testid='right-icon'>this is the right icon</span>
|
|
||||||
const { getByTestId } = render(<Button rightIcon={icon} />)
|
|
||||||
|
|
||||||
expect(getByTestId('right-icon')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `iconClassName` prop correctly', () => {
|
|
||||||
const icon = <span data-testid='icon'>just an icon</span>
|
|
||||||
const { getByTestId } = render(<Button rightIcon={icon} iconClassName='test-icon-class' />)
|
|
||||||
|
|
||||||
expect(getByTestId('icon').parentElement).toHaveClass('test-icon-class')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should show submenu indicator when `hasSubmenu=true`', () => {
|
|
||||||
const { getByTestId } = render(<Button hasSubmenu={true} />)
|
|
||||||
|
|
||||||
expect(getByTestId('button-submenu-indicator')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should set focus classes when `hasFocus=true`', () => {
|
|
||||||
const { container } = render(<Button hasFocus={true} color='primary' />)
|
|
||||||
const button = container.querySelector('button')
|
|
||||||
|
|
||||||
expect(button).toHaveClass(focusClasses['primary'])
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,60 +0,0 @@
|
|||||||
import { render, screen } from '@testing-library/react'
|
|
||||||
|
|
||||||
import Card from 'components/Card'
|
|
||||||
|
|
||||||
jest.mock('components/Text', () => {
|
|
||||||
return {
|
|
||||||
__esModule: true,
|
|
||||||
default: (props: any) =>
|
|
||||||
require('utils/testing').createMockComponent('mock-text-component', props),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('<Card />', () => {
|
|
||||||
const defaultProps = {
|
|
||||||
children: <></>,
|
|
||||||
}
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
jest.unmock('components/Text')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render', () => {
|
|
||||||
const { container } = render(<Card {...defaultProps} />)
|
|
||||||
expect(container).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `className` prop correctly', () => {
|
|
||||||
const testClass = 'test-class'
|
|
||||||
const { container } = render(<Card {...defaultProps} className={testClass} />)
|
|
||||||
expect(container.querySelector('section')).toHaveClass(testClass)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `contentClassName` prop correctly', () => {
|
|
||||||
const testClass = 'test-class'
|
|
||||||
const { container } = render(<Card {...defaultProps} contentClassName={testClass} />)
|
|
||||||
|
|
||||||
expect(container.querySelector('div')).toHaveClass(testClass)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `title` prop as string correctly', () => {
|
|
||||||
const testTitle = 'this-is-the-test-title'
|
|
||||||
const { queryByText } = render(<Card {...defaultProps} title={testTitle} />)
|
|
||||||
|
|
||||||
expect(queryByText(testTitle)).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `title` prop as element correctly', () => {
|
|
||||||
const testTitle = <p data-testid='test-title'>Test title</p>
|
|
||||||
const { queryByTestId } = render(<Card {...defaultProps} title={testTitle} />)
|
|
||||||
|
|
||||||
expect(queryByTestId('test-title')).toBeInTheDocument()
|
|
||||||
expect(queryByTestId('mock-text-component')).not.toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `id` prop as element correctly', () => {
|
|
||||||
const testId = 'test-id'
|
|
||||||
const { container } = render(<Card {...defaultProps} id={testId} />)
|
|
||||||
expect(container.querySelector(`section#${testId}`)).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,34 +0,0 @@
|
|||||||
import { render } from '@testing-library/react'
|
|
||||||
|
|
||||||
import { CircularProgress } from 'components/CircularProgress'
|
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
|
||||||
|
|
||||||
describe('<CircularProgress />', () => {
|
|
||||||
afterAll(() => {
|
|
||||||
localStorage.removeItem(LocalStorageKeys.REDUCE_MOTION)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render', () => {
|
|
||||||
const { container } = render(<CircularProgress />)
|
|
||||||
|
|
||||||
expect(container).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render `...` when animations disabled', () => {
|
|
||||||
localStorage.setItem(LocalStorageKeys.REDUCE_MOTION, 'true')
|
|
||||||
|
|
||||||
const { getByText } = render(<CircularProgress />)
|
|
||||||
const threeDots = getByText('...')
|
|
||||||
|
|
||||||
expect(threeDots).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render the component with animation classes when animations enabled', () => {
|
|
||||||
localStorage.setItem(LocalStorageKeys.REDUCE_MOTION, 'false')
|
|
||||||
|
|
||||||
const { container } = render(<CircularProgress />)
|
|
||||||
const progressWithAnimations = container.querySelector('.animate-progress')
|
|
||||||
|
|
||||||
expect(progressWithAnimations).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,65 +0,0 @@
|
|||||||
import { render } from '@testing-library/react'
|
|
||||||
|
|
||||||
import Modal from 'components/Modal'
|
|
||||||
import UnlockModal from 'components/Modals/Unlock'
|
|
||||||
import { BN_ONE, BN_ZERO } from 'constants/math'
|
|
||||||
import { TESTNET_VAULTS_META_DATA } from 'constants/vaults'
|
|
||||||
import useStore from 'store'
|
|
||||||
import { BN } from 'utils/helpers'
|
|
||||||
|
|
||||||
jest.mock('components/Modal')
|
|
||||||
const mockedModal = jest.mocked(Modal).mockImplementation(() => <div>Mock</div>)
|
|
||||||
|
|
||||||
const mockedDepositedVault: DepositedVault = {
|
|
||||||
...TESTNET_VAULTS_META_DATA[0],
|
|
||||||
status: 'active',
|
|
||||||
apy: 1,
|
|
||||||
apr: null,
|
|
||||||
ltv: {
|
|
||||||
max: 0.65,
|
|
||||||
liq: 0.7,
|
|
||||||
},
|
|
||||||
amounts: {
|
|
||||||
primary: BN_ONE,
|
|
||||||
secondary: BN_ONE,
|
|
||||||
locked: BN_ONE,
|
|
||||||
unlocked: BN_ONE,
|
|
||||||
unlocking: BN_ONE,
|
|
||||||
},
|
|
||||||
values: {
|
|
||||||
primary: BN_ZERO,
|
|
||||||
secondary: BN_ZERO,
|
|
||||||
unlocked: BN_ZERO,
|
|
||||||
unlocking: BN_ZERO,
|
|
||||||
},
|
|
||||||
cap: {
|
|
||||||
denom: 'mock',
|
|
||||||
max: BN(10),
|
|
||||||
used: BN_ONE,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('<UnlockModal />', () => {
|
|
||||||
afterAll(() => {
|
|
||||||
useStore.clearState()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render', () => {
|
|
||||||
const { container } = render(<UnlockModal />)
|
|
||||||
expect(container).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('should set content correctly', () => {
|
|
||||||
it('should have no content when no modal is present in store', () => {
|
|
||||||
useStore.setState({ unlockModal: null })
|
|
||||||
render(<UnlockModal />)
|
|
||||||
expect(mockedModal).toHaveBeenCalledTimes(0)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have content when modal is present in store', () => {
|
|
||||||
useStore.setState({ unlockModal: { vault: mockedDepositedVault } })
|
|
||||||
render(<UnlockModal />)
|
|
||||||
expect(mockedModal).toHaveBeenCalledTimes(1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,32 +0,0 @@
|
|||||||
import { render } from '@testing-library/react'
|
|
||||||
import * as rrd from 'react-router-dom'
|
|
||||||
|
|
||||||
import PageMetadata from 'components/PageMetadata'
|
|
||||||
import PAGE_METADATA from 'constants/pageMetadata'
|
|
||||||
|
|
||||||
jest.mock('react-router-dom')
|
|
||||||
const mockedUseLocation = rrd.useLocation as jest.Mock
|
|
||||||
|
|
||||||
describe('<PageMetadata />', () => {
|
|
||||||
afterAll(() => {
|
|
||||||
jest.clearAllMocks()
|
|
||||||
})
|
|
||||||
|
|
||||||
Object.keys(PAGE_METADATA).forEach((page) => {
|
|
||||||
it(`should render correct ${page} metadata`, () => {
|
|
||||||
const pageKey = page as keyof typeof PAGE_METADATA
|
|
||||||
const pageMetadata = PAGE_METADATA[pageKey]
|
|
||||||
|
|
||||||
mockedUseLocation.mockReturnValue({ pathname: pageKey })
|
|
||||||
|
|
||||||
const { container } = render(<PageMetadata />)
|
|
||||||
const titleElement = container.querySelector('title')
|
|
||||||
const descriptionElement = container.querySelector('meta[name="description"]')
|
|
||||||
const keywordsElement = container.querySelector('meta[name="keywords"]')
|
|
||||||
|
|
||||||
expect(titleElement).toHaveTextContent(pageMetadata.title)
|
|
||||||
expect(descriptionElement).toHaveAttribute('content', pageMetadata.description)
|
|
||||||
expect(keywordsElement).toHaveAttribute('content', pageMetadata.keywords)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,98 +0,0 @@
|
|||||||
import { fireEvent, render } from '@testing-library/react'
|
|
||||||
import BigNumber from 'bignumber.js'
|
|
||||||
|
|
||||||
import TokenInput from 'components/TokenInput'
|
|
||||||
import { ASSETS } from 'constants/assets'
|
|
||||||
|
|
||||||
jest.mock('components/DisplayCurrency', () => {
|
|
||||||
return {
|
|
||||||
__esModule: true,
|
|
||||||
default: (props: any) =>
|
|
||||||
require('utils/testing').createMockComponent('mock-display-currency-component', props),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('<TokenInput />', () => {
|
|
||||||
const asset = ASSETS[0]
|
|
||||||
const defaultProps = {
|
|
||||||
amount: new BigNumber(1),
|
|
||||||
asset,
|
|
||||||
max: new BigNumber(100),
|
|
||||||
onChangeAsset: jest.fn(),
|
|
||||||
onChange: jest.fn(),
|
|
||||||
}
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
jest.unmock('components/DisplayCurrency')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render', () => {
|
|
||||||
const { container } = render(<TokenInput warningMessages={[]} {...defaultProps} />)
|
|
||||||
expect(container).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `className` prop correctly', () => {
|
|
||||||
const testClass = 'test-class'
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<TokenInput warningMessages={[]} {...defaultProps} className={testClass} />,
|
|
||||||
)
|
|
||||||
expect(getByTestId('token-input-component')).toHaveClass(testClass)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `disabled` prop correctly', () => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<TokenInput warningMessages={[]} {...defaultProps} disabled={true} />,
|
|
||||||
)
|
|
||||||
expect(getByTestId('token-input-component')).toHaveClass('pointer-events-none', 'opacity-50')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `maxText` prop correctly', () => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<TokenInput warningMessages={[]} {...defaultProps} maxText='Max' />,
|
|
||||||
)
|
|
||||||
expect(getByTestId('token-input-max-button')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('should render the max button', () => {
|
|
||||||
it('when `maxText` prop is defined', () => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<TokenInput warningMessages={[]} {...defaultProps} maxText='Max' />,
|
|
||||||
)
|
|
||||||
expect(getByTestId('token-input-max-button')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
it('not when `maxText` prop is undefined', () => {
|
|
||||||
const { queryByTestId } = render(<TokenInput warningMessages={[]} {...defaultProps} />)
|
|
||||||
expect(queryByTestId('token-input-max-button')).not.toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('should render <Select />', () => {
|
|
||||||
it('when `hasSelect` prop is true and balances is defined', () => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<TokenInput warningMessages={[]} {...defaultProps} balances={[]} hasSelect />,
|
|
||||||
)
|
|
||||||
expect(getByTestId('select-component')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
it('not when `hasSelect` prop is true and balances is not defined', () => {
|
|
||||||
const { queryByTestId } = render(
|
|
||||||
<TokenInput warningMessages={[]} {...defaultProps} hasSelect />,
|
|
||||||
)
|
|
||||||
expect(queryByTestId('select-component')).not.toBeInTheDocument()
|
|
||||||
})
|
|
||||||
it('not when `hasSelect` prop is false and balances is defined', () => {
|
|
||||||
const { queryByTestId } = render(
|
|
||||||
<TokenInput warningMessages={[]} {...defaultProps} balances={[]} />,
|
|
||||||
)
|
|
||||||
expect(queryByTestId('select-component')).not.toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should call onMaxBtnClick when the user clicks on max button', () => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<TokenInput warningMessages={[]} {...defaultProps} maxText='max' />,
|
|
||||||
)
|
|
||||||
const maxBtn = getByTestId('token-input-max-button')
|
|
||||||
fireEvent.click(maxBtn)
|
|
||||||
expect(defaultProps.onChange).toBeCalledWith(defaultProps.max)
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,45 +0,0 @@
|
|||||||
import { render } from '@testing-library/react'
|
|
||||||
|
|
||||||
import { Tooltip } from 'components/Tooltip'
|
|
||||||
|
|
||||||
describe('<Tooltip />', () => {
|
|
||||||
const defaultProps = {
|
|
||||||
content: <></>,
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should render', () => {
|
|
||||||
const { container } = render(<Tooltip {...defaultProps} type='info' />)
|
|
||||||
expect(container).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `children` prop correctly', () => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<Tooltip {...defaultProps} type='info'>
|
|
||||||
<p data-testid='test-child'>Test text</p>
|
|
||||||
</Tooltip>,
|
|
||||||
)
|
|
||||||
expect(getByTestId('test-child')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `className` prop correctly', () => {
|
|
||||||
const testClass = 'test-class'
|
|
||||||
const { container } = render(<Tooltip {...defaultProps} type='info' className={testClass} />)
|
|
||||||
expect(container.getElementsByClassName(testClass)).toHaveLength(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('should handle `underline` prop correctly', () => {
|
|
||||||
it('should have border class when children are passed', () => {
|
|
||||||
const { container } = render(
|
|
||||||
<Tooltip {...defaultProps} type='info' underline>
|
|
||||||
<></>
|
|
||||||
</Tooltip>,
|
|
||||||
)
|
|
||||||
expect(container.getElementsByClassName('border-b-1')).toHaveLength(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not have border class when children are passed', () => {
|
|
||||||
const { container } = render(<Tooltip {...defaultProps} type='info' underline />)
|
|
||||||
expect(container.getElementsByClassName('border-b-1')).toHaveLength(0)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,43 +0,0 @@
|
|||||||
import { render } from '@testing-library/react'
|
|
||||||
|
|
||||||
import TooltipContent from 'components/Tooltip/TooltipContent'
|
|
||||||
|
|
||||||
describe('<Tooltip />', () => {
|
|
||||||
const defaultProps = {
|
|
||||||
content: <></>,
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should render', () => {
|
|
||||||
const { container } = render(<TooltipContent {...defaultProps} type='info' />)
|
|
||||||
expect(container).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle `type` prop correctly', () => {
|
|
||||||
const types = { info: 'bg-white/20', warning: 'bg-warning', error: 'bg-error' }
|
|
||||||
Object.entries(types).forEach(([key, value]) => {
|
|
||||||
const { container } = render(<TooltipContent {...defaultProps} type={key as TooltipType} />)
|
|
||||||
expect(container.getElementsByClassName(value)).toHaveLength(1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('should handle `content` props correctly', () => {
|
|
||||||
it('should render Text component when type is string', () => {
|
|
||||||
const testText = 'testText'
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<TooltipContent {...defaultProps} type='info' content={testText} />,
|
|
||||||
)
|
|
||||||
const textComponent = getByTestId('text-component')
|
|
||||||
expect(textComponent).toHaveTextContent(testText)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render content when type is ReactNode', () => {
|
|
||||||
const testNode = <p data-testid='test-node'>Test node</p>
|
|
||||||
const { queryByTestId } = render(
|
|
||||||
<TooltipContent {...defaultProps} type='info' content={testNode} />,
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(queryByTestId('text-component')).not.toBeInTheDocument()
|
|
||||||
expect(queryByTestId('test-node')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,60 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
collectCoverage: true,
|
|
||||||
coverageProvider: 'v8',
|
|
||||||
collectCoverageFrom: [
|
|
||||||
'**/*.{js,jsx,ts,tsx}',
|
|
||||||
'!**/*.d.ts',
|
|
||||||
'!**/node_modules/**',
|
|
||||||
'!<rootDir>/out/**',
|
|
||||||
'!<rootDir>/.next/**',
|
|
||||||
'!<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)
|
|
||||||
// https://jestjs.io/docs/webpack#mocking-css-modules
|
|
||||||
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
|
|
||||||
|
|
||||||
// Handle CSS imports (without CSS modules)
|
|
||||||
'^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
|
|
||||||
|
|
||||||
// Handle image imports
|
|
||||||
// https://jestjs.io/docs/webpack#handling-static-assets
|
|
||||||
'^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp)$/i': `<rootDir>/__mocks__/fileMock.js`,
|
|
||||||
'^.+\\.svg$': `<rootDir>/__mocks__/svgMock.js`,
|
|
||||||
|
|
||||||
// Handle module aliases
|
|
||||||
'^app/(.*)$': '<rootDir>/src/app/$1',
|
|
||||||
'^api/(.*)$': '<rootDir>/src/api/$1',
|
|
||||||
'^components/(.*)$': '<rootDir>/src/components/$1',
|
|
||||||
'^constants/(.*)$': '<rootDir>/src/constants/$1',
|
|
||||||
'^fonts/(.*)$': '<rootDir>/src/fonts/$1',
|
|
||||||
'^hooks/(.*)$': '<rootDir>/src/hooks/$1',
|
|
||||||
'^pages/(.*)$': '<rootDir>/src/pages/$1',
|
|
||||||
'^store/(.*)$': '<rootDir>/src/store/$1',
|
|
||||||
'^styles/(.*)$': '<rootDir>/src/styles/$1',
|
|
||||||
'^types/(.*)$': '<rootDir>/src/types/$1',
|
|
||||||
'^utils/(.*)$': '<rootDir>/src/utils/$1',
|
|
||||||
'^store': '<rootDir>/src/store',
|
|
||||||
},
|
|
||||||
// Add more setup options before each test is run
|
|
||||||
setupFilesAfterEnv: [
|
|
||||||
'<rootDir>/jest.setup.js',
|
|
||||||
'<rootDir>/__mocks__/store.js',
|
|
||||||
'<rootDir>/__mocks__/helmet.js',
|
|
||||||
],
|
|
||||||
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
|
|
||||||
testEnvironment: 'jsdom',
|
|
||||||
transform: {
|
|
||||||
// Use babel-jest to transpile tests with the next/babel preset
|
|
||||||
// https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
|
|
||||||
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
|
|
||||||
},
|
|
||||||
transformIgnorePatterns: ['/node_modules/', '^.+\\.module\\.(css|sass|scss)$'],
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
import '@testing-library/jest-dom/extend-expect'
|
|
14
package.json
14
package.json
@ -1,14 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mars-v2-frontend",
|
"name": "mars-v2-frontend",
|
||||||
"version": "2.1.2",
|
"version": "2.2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn validate-env && next build",
|
"build": "yarn validate-env && next build",
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"test": "jest",
|
|
||||||
"test:cov": "jest --coverage",
|
|
||||||
"lint": "eslint ./src/ && yarn prettier-check",
|
"lint": "eslint ./src/ && yarn prettier-check",
|
||||||
"format": "eslint ./src/ ./__tests__/ --fix && prettier --write ./src/ ./__tests__/",
|
"format": "eslint ./src/ --fix && prettier --write ./src/ ",
|
||||||
"prettier-check": "prettier --ignore-path .gitignore --check ./src/",
|
"prettier-check": "prettier --ignore-path .gitignore --check ./src/",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"validate-env": "node ./validate-env",
|
"validate-env": "node ./validate-env",
|
||||||
@ -17,8 +15,8 @@
|
|||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.ts*": [
|
"*.ts*": [
|
||||||
"eslint ./src/ ./__tests__/ --fix",
|
"eslint ./src/ --fix",
|
||||||
"prettier --write ./src/ ./__tests__/"
|
"prettier --write ./src/"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -57,7 +55,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@svgr/webpack": "^8.1.0",
|
"@svgr/webpack": "^8.1.0",
|
||||||
"@testing-library/jest-dom": "^5.17.0",
|
|
||||||
"@testing-library/react": "^14.0.0",
|
"@testing-library/react": "^14.0.0",
|
||||||
"@types/debounce-promise": "^3.1.9",
|
"@types/debounce-promise": "^3.1.9",
|
||||||
"@types/lodash.debounce": "^4.0.9",
|
"@types/lodash.debounce": "^4.0.9",
|
||||||
@ -67,7 +64,6 @@
|
|||||||
"@types/react-dom": "18.2.15",
|
"@types/react-dom": "18.2.15",
|
||||||
"@types/react-helmet": "^6.1.11",
|
"@types/react-helmet": "^6.1.11",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"babel-jest": "^29.7.0",
|
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"dotenv-cli": "^7.3.0",
|
"dotenv-cli": "^7.3.0",
|
||||||
"eslint": "^8.54.0",
|
"eslint": "^8.54.0",
|
||||||
@ -75,8 +71,6 @@
|
|||||||
"eslint-plugin-import": "^2.29.0",
|
"eslint-plugin-import": "^2.29.0",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "^29.7.0",
|
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
|
||||||
"lint-staged": "^15.2.0",
|
"lint-staged": "^15.2.0",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"prettier-plugin-tailwindcss": "^0.5.6",
|
"prettier-plugin-tailwindcss": "^0.5.6",
|
||||||
|
16
public/images/tokens/ntrn.svg
Normal file
16
public/images/tokens/ntrn.svg
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
fill="#FFF"
|
||||||
|
d="M23.6,14.9C22,21.3,15.5,25.2,9,23.6C2.6,22-1.3,15.5,0.3,9.1S8.4-1.2,14.8,0.4C21.3,2,25.2,8.5,23.6,14.9
|
||||||
|
L23.6,14.9L23.6,14.9z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#000"
|
||||||
|
d="M12,15.1c-1.7,0-3.1-1.4-3.1-3.1c0-0.6,0.2-1.2,0.5-1.6L5.4,7.1v11.5h11.5l-3.3-3.9C13.1,15,12.5,15.1,12,15.1z
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#000"
|
||||||
|
d="M6.4,5.4l3.5,4.2c0.5-0.5,1.3-0.8,2-0.8c1.7,0,3.1,1.4,3.1,3.1c0,0.7-0.3,1.4-0.7,2l4.1,3.6V5.4H6.4z"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 557 B |
BIN
public/images/wallets/vectis.png
Normal file
BIN
public/images/wallets/vectis.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 3.9 KiB |
@ -4,10 +4,13 @@ import getDepositedVaults from 'api/vaults/getDepositedVaults'
|
|||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { Positions } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
import { Positions } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||||
|
|
||||||
export default async function getAccount(accountId?: string): Promise<Account> {
|
export default async function getAccount(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
accountId?: string,
|
||||||
|
): Promise<Account> {
|
||||||
if (!accountId) return new Promise((_, reject) => reject('No account ID found'))
|
if (!accountId) return new Promise((_, reject) => reject('No account ID found'))
|
||||||
|
|
||||||
const creditManagerQueryClient = await getCreditManagerQueryClient()
|
const creditManagerQueryClient = await getCreditManagerQueryClient(chainConfig)
|
||||||
|
|
||||||
const accountPosition: Positions = await cacheFn(
|
const accountPosition: Positions = await cacheFn(
|
||||||
() => creditManagerQueryClient.positions({ accountId: accountId }),
|
() => creditManagerQueryClient.positions({ accountId: accountId }),
|
||||||
@ -17,7 +20,7 @@ export default async function getAccount(accountId?: string): Promise<Account> {
|
|||||||
|
|
||||||
const accountKind = await creditManagerQueryClient.accountKind({ accountId: accountId })
|
const accountKind = await creditManagerQueryClient.accountKind({ accountId: accountId })
|
||||||
|
|
||||||
const depositedVaults = await getDepositedVaults(accountId, accountPosition)
|
const depositedVaults = await getDepositedVaults(accountId, chainConfig, accountPosition)
|
||||||
|
|
||||||
if (accountPosition) {
|
if (accountPosition) {
|
||||||
return {
|
return {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
|
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
|
||||||
|
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
import { ICNSQueryClient } from 'types/classes/ICNSClient.client'
|
import { ICNSQueryClient } from 'types/classes/ICNSClient.client'
|
||||||
import { MarsAccountNftQueryClient } from 'types/generated/mars-account-nft/MarsAccountNft.client'
|
import { MarsAccountNftQueryClient } from 'types/generated/mars-account-nft/MarsAccountNft.client'
|
||||||
import { MarsCreditManagerQueryClient } from 'types/generated/mars-credit-manager/MarsCreditManager.client'
|
import { MarsCreditManagerQueryClient } from 'types/generated/mars-credit-manager/MarsCreditManager.client'
|
||||||
@ -11,139 +10,166 @@ import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.cl
|
|||||||
import { MarsRedBankQueryClient } from 'types/generated/mars-red-bank/MarsRedBank.client'
|
import { MarsRedBankQueryClient } from 'types/generated/mars-red-bank/MarsRedBank.client'
|
||||||
import { MarsSwapperOsmosisQueryClient } from 'types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client'
|
import { MarsSwapperOsmosisQueryClient } from 'types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client'
|
||||||
|
|
||||||
let _cosmWasmClient: CosmWasmClient
|
let _cosmWasmClient: Map<string, CosmWasmClient> = new Map()
|
||||||
let _accountNftQueryClient: MarsAccountNftQueryClient
|
let _accountNftQueryClient: Map<string, MarsAccountNftQueryClient> = new Map()
|
||||||
let _creditManagerQueryClient: MarsCreditManagerQueryClient
|
let _creditManagerQueryClient: Map<string, MarsCreditManagerQueryClient> = new Map()
|
||||||
let _oracleQueryClient: MarsOracleOsmosisQueryClient
|
let _oracleQueryClient: Map<string, MarsOracleOsmosisQueryClient> = new Map()
|
||||||
let _redBankQueryClient: MarsRedBankQueryClient
|
let _redBankQueryClient: Map<string, MarsRedBankQueryClient> = new Map()
|
||||||
let _paramsQueryClient: MarsParamsQueryClient
|
let _paramsQueryClient: Map<string, MarsParamsQueryClient> = new Map()
|
||||||
let _incentivesQueryClient: MarsIncentivesQueryClient
|
let _incentivesQueryClient: Map<string, MarsIncentivesQueryClient> = new Map()
|
||||||
let _swapperOsmosisClient: MarsSwapperOsmosisQueryClient
|
let _swapperOsmosisClient: Map<string, MarsSwapperOsmosisQueryClient> = new Map()
|
||||||
let _ICNSQueryClient: ICNSQueryClient
|
let _ICNSQueryClient: Map<string, ICNSQueryClient> = new Map()
|
||||||
|
|
||||||
const getClient = async () => {
|
const getClient = async (rpc: string) => {
|
||||||
try {
|
try {
|
||||||
if (!_cosmWasmClient) {
|
if (!_cosmWasmClient.get(rpc)) {
|
||||||
_cosmWasmClient = await CosmWasmClient.connect(ENV.URL_RPC)
|
const client = await CosmWasmClient.connect(rpc)
|
||||||
|
_cosmWasmClient.set(rpc, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
return _cosmWasmClient
|
return _cosmWasmClient.get(rpc)!
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAccountNftQueryClient = async () => {
|
const getAccountNftQueryClient = async (chainConfig: ChainConfig) => {
|
||||||
try {
|
try {
|
||||||
if (!_accountNftQueryClient) {
|
const contract = chainConfig.contracts.accountNft
|
||||||
const client = await getClient()
|
const rpc = chainConfig.endpoints.rpc
|
||||||
_accountNftQueryClient = new MarsAccountNftQueryClient(client, ENV.ADDRESS_ACCOUNT_NFT)
|
const key = rpc + contract
|
||||||
|
|
||||||
|
if (!_accountNftQueryClient.get(key)) {
|
||||||
|
const client = await getClient(rpc)
|
||||||
|
_accountNftQueryClient.set(key, new MarsAccountNftQueryClient(client, contract))
|
||||||
}
|
}
|
||||||
|
|
||||||
return _accountNftQueryClient
|
return _accountNftQueryClient.get(key)!
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCreditManagerQueryClient = async () => {
|
const getCreditManagerQueryClient = async (chainConfig: ChainConfig) => {
|
||||||
try {
|
try {
|
||||||
if (!_creditManagerQueryClient) {
|
const contract = chainConfig.contracts.creditManager
|
||||||
const client = await getClient()
|
const rpc = chainConfig.endpoints.rpc
|
||||||
_creditManagerQueryClient = new MarsCreditManagerQueryClient(
|
const key = rpc + contract
|
||||||
client,
|
|
||||||
ENV.ADDRESS_CREDIT_MANAGER,
|
if (!_creditManagerQueryClient.get(key)) {
|
||||||
)
|
const client = await getClient(rpc)
|
||||||
|
_creditManagerQueryClient.set(key, new MarsCreditManagerQueryClient(client, contract))
|
||||||
}
|
}
|
||||||
|
|
||||||
return _creditManagerQueryClient
|
return _creditManagerQueryClient.get(key)!
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getParamsQueryClient = async () => {
|
const getParamsQueryClient = async (chainConfig: ChainConfig) => {
|
||||||
try {
|
try {
|
||||||
if (!_paramsQueryClient) {
|
const contract = chainConfig.contracts.params
|
||||||
const client = await getClient()
|
const rpc = chainConfig.endpoints.rpc
|
||||||
_paramsQueryClient = new MarsParamsQueryClient(client, ENV.ADDRESS_PARAMS)
|
const key = rpc + contract
|
||||||
|
|
||||||
|
if (!_paramsQueryClient.get(key)) {
|
||||||
|
const client = await getClient(rpc)
|
||||||
|
_paramsQueryClient.set(key, new MarsParamsQueryClient(client, contract))
|
||||||
}
|
}
|
||||||
|
|
||||||
return _paramsQueryClient
|
return _paramsQueryClient.get(key)!
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getOracleQueryClient = async () => {
|
const getOracleQueryClient = async (chainConfig: ChainConfig) => {
|
||||||
try {
|
try {
|
||||||
if (!_oracleQueryClient) {
|
const contract = chainConfig.contracts.oracle
|
||||||
const client = await getClient()
|
const rpc = chainConfig.endpoints.rpc
|
||||||
_oracleQueryClient = new MarsOracleOsmosisQueryClient(client, ENV.ADDRESS_ORACLE)
|
const key = rpc + contract
|
||||||
|
|
||||||
|
if (!_oracleQueryClient.get(key)) {
|
||||||
|
const client = await getClient(rpc)
|
||||||
|
_oracleQueryClient.set(key, new MarsOracleOsmosisQueryClient(client, contract))
|
||||||
}
|
}
|
||||||
|
|
||||||
return _oracleQueryClient
|
return _oracleQueryClient.get(key)!
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRedBankQueryClient = async () => {
|
const getRedBankQueryClient = async (chainConfig: ChainConfig) => {
|
||||||
try {
|
try {
|
||||||
if (!_redBankQueryClient) {
|
const contract = chainConfig.contracts.redBank
|
||||||
const client = await getClient()
|
const rpc = chainConfig.endpoints.rpc
|
||||||
_redBankQueryClient = new MarsRedBankQueryClient(client, ENV.ADDRESS_RED_BANK)
|
const key = rpc + contract
|
||||||
|
|
||||||
|
if (!_redBankQueryClient.get(key)) {
|
||||||
|
const client = await getClient(rpc)
|
||||||
|
_redBankQueryClient.set(key, new MarsRedBankQueryClient(client, contract))
|
||||||
}
|
}
|
||||||
|
|
||||||
return _redBankQueryClient
|
return _redBankQueryClient.get(key)!
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getVaultQueryClient = async (address: string) => {
|
const getVaultQueryClient = async (chainConfig: ChainConfig, address: string) => {
|
||||||
try {
|
try {
|
||||||
const client = await getClient()
|
const client = await getClient(chainConfig.endpoints.rpc)
|
||||||
return new MarsMockVaultQueryClient(client, address)
|
return new MarsMockVaultQueryClient(client, address)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getIncentivesQueryClient = async () => {
|
const getIncentivesQueryClient = async (chainConfig: ChainConfig) => {
|
||||||
try {
|
try {
|
||||||
if (!_incentivesQueryClient) {
|
const contract = chainConfig.contracts.incentives
|
||||||
const client = await getClient()
|
const rpc = chainConfig.endpoints.rpc
|
||||||
_incentivesQueryClient = new MarsIncentivesQueryClient(client, ENV.ADDRESS_INCENTIVES)
|
const key = rpc + contract
|
||||||
|
if (!_incentivesQueryClient.get(key)) {
|
||||||
|
const client = await getClient(rpc)
|
||||||
|
_incentivesQueryClient.set(key, new MarsIncentivesQueryClient(client, contract))
|
||||||
}
|
}
|
||||||
|
|
||||||
return _incentivesQueryClient
|
return _incentivesQueryClient.get(key)!
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSwapperQueryClient = async () => {
|
const getSwapperQueryClient = async (chainConfig: ChainConfig) => {
|
||||||
try {
|
try {
|
||||||
if (!_swapperOsmosisClient) {
|
const contract = chainConfig.contracts.swapper
|
||||||
const client = await getClient()
|
const rpc = chainConfig.endpoints.rpc
|
||||||
_swapperOsmosisClient = new MarsSwapperOsmosisQueryClient(client, ENV.ADDRESS_SWAPPER)
|
const key = rpc + contract
|
||||||
|
if (!_swapperOsmosisClient.get(key)) {
|
||||||
|
const client = await getClient(rpc)
|
||||||
|
_swapperOsmosisClient.set(key, new MarsSwapperOsmosisQueryClient(client, contract))
|
||||||
}
|
}
|
||||||
|
|
||||||
return _swapperOsmosisClient
|
return _swapperOsmosisClient.get(key)!
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getICNSQueryClient = async () => {
|
const getICNSQueryClient = async (chainConfig: ChainConfig) => {
|
||||||
try {
|
try {
|
||||||
if (!_ICNSQueryClient) {
|
const contract = chainConfig.contracts.params
|
||||||
const client = await getClient()
|
const rpc = chainConfig.endpoints.rpc
|
||||||
_ICNSQueryClient = new ICNSQueryClient(client)
|
const key = rpc + contract
|
||||||
|
if (!_ICNSQueryClient.get(key)) {
|
||||||
|
const client = await getClient(rpc)
|
||||||
|
_ICNSQueryClient.set(key, new ICNSQueryClient(client))
|
||||||
}
|
}
|
||||||
|
|
||||||
return _ICNSQueryClient
|
return _ICNSQueryClient.get(key)!
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { cacheFn, stakingAprCache } from 'api/cache'
|
import { cacheFn, stakingAprCache } from 'api/cache'
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
|
|
||||||
export default async function getStakingAprs() {
|
export default async function getStakingAprs(url: string) {
|
||||||
try {
|
try {
|
||||||
return cacheFn(() => fetchAprs(), stakingAprCache, `stakingAprs`)
|
return cacheFn(() => fetchAprs(url), stakingAprCache, `stakingAprs`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
@ -13,9 +12,7 @@ interface StakingAprResponse {
|
|||||||
stats: StakingApr[]
|
stats: StakingApr[]
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAprs(): Promise<StakingApr[]> {
|
async function fetchAprs(url: string): Promise<StakingApr[]> {
|
||||||
const url = ENV.STRIDE_APRS
|
|
||||||
|
|
||||||
const response = await fetch(url)
|
const response = await fetch(url)
|
||||||
const body = (await response.json()) as StakingAprResponse
|
const body = (await response.json()) as StakingAprResponse
|
||||||
return body.stats
|
return body.stats
|
||||||
|
@ -4,12 +4,13 @@ import getAccounts from 'api/wallets/getAccounts'
|
|||||||
import { calculateAccountLeverage, getAccountPositionValues, isAccountEmpty } from 'utils/accounts'
|
import { calculateAccountLeverage, getAccountPositionValues, isAccountEmpty } from 'utils/accounts'
|
||||||
|
|
||||||
export default async function getHLSStakingAccounts(
|
export default async function getHLSStakingAccounts(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
address?: string,
|
address?: string,
|
||||||
): Promise<HLSAccountWithStrategy[]> {
|
): Promise<HLSAccountWithStrategy[]> {
|
||||||
const accounts = await getAccounts('high_levered_strategy', address)
|
const accounts = await getAccounts('high_levered_strategy', chainConfig, address)
|
||||||
const activeAccounts = accounts.filter((account) => !isAccountEmpty(account))
|
const activeAccounts = accounts.filter((account) => !isAccountEmpty(account))
|
||||||
const hlsStrategies = await getHLSStakingAssets()
|
const hlsStrategies = await getHLSStakingAssets(chainConfig)
|
||||||
const prices = await getPrices()
|
const prices = await getPrices(chainConfig)
|
||||||
const hlsAccountsWithStrategy: HLSAccountWithStrategy[] = []
|
const hlsAccountsWithStrategy: HLSAccountWithStrategy[] = []
|
||||||
|
|
||||||
activeAccounts.forEach((account) => {
|
activeAccounts.forEach((account) => {
|
||||||
@ -21,7 +22,11 @@ export default async function getHLSStakingAccounts(
|
|||||||
|
|
||||||
if (!strategy) return
|
if (!strategy) return
|
||||||
|
|
||||||
const [deposits, lends, debts, vaults] = getAccountPositionValues(account, prices)
|
const [deposits, lends, debts, vaults] = getAccountPositionValues(
|
||||||
|
account,
|
||||||
|
prices,
|
||||||
|
chainConfig.assets,
|
||||||
|
)
|
||||||
|
|
||||||
hlsAccountsWithStrategy.push({
|
hlsAccountsWithStrategy.push({
|
||||||
...account,
|
...account,
|
||||||
@ -31,7 +36,7 @@ export default async function getHLSStakingAccounts(
|
|||||||
debt: debts,
|
debt: debts,
|
||||||
total: deposits,
|
total: deposits,
|
||||||
},
|
},
|
||||||
leverage: calculateAccountLeverage(account, prices).toNumber(),
|
leverage: calculateAccountLeverage(account, prices, chainConfig.assets).toNumber(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,28 +1,29 @@
|
|||||||
import { getParamsQueryClient } from 'api/cosmwasm-client'
|
import { getParamsQueryClient } from 'api/cosmwasm-client'
|
||||||
import getStakingAprs from 'api/hls/getAprs'
|
import getStakingAprs from 'api/hls/getAprs'
|
||||||
import getAssetParams from 'api/params/getAssetParams'
|
import getAssetParams from 'api/params/getAssetParams'
|
||||||
import { getAssetByDenom, getStakingAssets } from 'utils/assets'
|
import { byDenom } from 'utils/array'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import { resolveHLSStrategies } from 'utils/resolvers'
|
import { resolveHLSStrategies } from 'utils/resolvers'
|
||||||
|
|
||||||
export default async function getHLSStakingAssets() {
|
export default async function getHLSStakingAssets(chainConfig: ChainConfig) {
|
||||||
const stakingAssetDenoms = getStakingAssets().map((asset) => asset.denom)
|
const stakingAssetDenoms = chainConfig.assets
|
||||||
const assetParams = await getAssetParams()
|
.filter((asset) => asset.isStaking)
|
||||||
|
.map((asset) => asset.denom)
|
||||||
|
const assetParams = await getAssetParams(chainConfig)
|
||||||
const HLSAssets = assetParams
|
const HLSAssets = assetParams
|
||||||
.filter((asset) => stakingAssetDenoms.includes(asset.denom))
|
.filter((asset) => stakingAssetDenoms.includes(asset.denom))
|
||||||
.filter((asset) => asset.credit_manager.hls)
|
.filter((asset) => asset.credit_manager.hls)
|
||||||
const strategies = resolveHLSStrategies('coin', HLSAssets)
|
const strategies = resolveHLSStrategies('coin', HLSAssets)
|
||||||
|
const client = await getParamsQueryClient(chainConfig)
|
||||||
const client = await getParamsQueryClient()
|
|
||||||
const depositCaps$ = strategies.map((strategy) =>
|
const depositCaps$ = strategies.map((strategy) =>
|
||||||
client.totalDeposit({ denom: strategy.denoms.deposit }),
|
client.totalDeposit({ denom: strategy.denoms.deposit }),
|
||||||
)
|
)
|
||||||
|
|
||||||
const aprs = await getStakingAprs()
|
const aprs = await getStakingAprs(chainConfig.endpoints.aprs.stride)
|
||||||
|
|
||||||
return Promise.all(depositCaps$).then((depositCaps) => {
|
return Promise.all(depositCaps$).then((depositCaps) => {
|
||||||
return depositCaps.map((depositCap, index) => {
|
return depositCaps.map((depositCap, index) => {
|
||||||
const borrowSymbol = getAssetByDenom(strategies[index].denoms.borrow)?.symbol
|
const borrowSymbol = chainConfig.assets.find(byDenom(strategies[index].denoms.borrow))?.symbol
|
||||||
return {
|
return {
|
||||||
...strategies[index],
|
...strategies[index],
|
||||||
depositCap: {
|
depositCap: {
|
||||||
|
@ -4,10 +4,10 @@ import { getVaultConfigs } from 'api/vaults/getVaultConfigs'
|
|||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import { resolveHLSStrategies } from 'utils/resolvers'
|
import { resolveHLSStrategies } from 'utils/resolvers'
|
||||||
|
|
||||||
export default async function getHLSVaults() {
|
export default async function getHLSVaults(chainConfig: ChainConfig) {
|
||||||
const assetParams = await getAssetParams()
|
const assetParams = await getAssetParams(chainConfig)
|
||||||
const client = await getCreditManagerQueryClient()
|
const client = await getCreditManagerQueryClient(chainConfig)
|
||||||
const vaultConfigs = await getVaultConfigs()
|
const vaultConfigs = await getVaultConfigs(chainConfig)
|
||||||
const HLSAssets = assetParams.filter((asset) => asset.credit_manager.hls)
|
const HLSAssets = assetParams.filter((asset) => asset.credit_manager.hls)
|
||||||
const strategies = resolveHLSStrategies('vault', HLSAssets)
|
const strategies = resolveHLSStrategies('vault', HLSAssets)
|
||||||
|
|
||||||
|
@ -2,28 +2,28 @@ import getTotalActiveEmissionValue from 'api/incentives/getTotalActiveEmissionVa
|
|||||||
import getMarket from 'api/markets/getMarket'
|
import getMarket from 'api/markets/getMarket'
|
||||||
import getUnderlyingLiquidityAmount from 'api/markets/getMarketUnderlyingLiquidityAmount'
|
import getUnderlyingLiquidityAmount from 'api/markets/getMarketUnderlyingLiquidityAmount'
|
||||||
import getPrice from 'api/prices/getPrice'
|
import getPrice from 'api/prices/getPrice'
|
||||||
import { ASSETS } from 'constants/assets'
|
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { SECONDS_IN_A_YEAR } from 'utils/constants'
|
import { SECONDS_IN_A_YEAR } from 'utils/constants'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
export default async function calculateAssetIncentivesApy(
|
export default async function calculateAssetIncentivesApy(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
denom: string,
|
denom: string,
|
||||||
): Promise<BigNumber | null> {
|
): Promise<BigNumber | null> {
|
||||||
try {
|
try {
|
||||||
const [totalActiveEmissionValue, market] = await Promise.all([
|
const [totalActiveEmissionValue, market] = await Promise.all([
|
||||||
getTotalActiveEmissionValue(denom),
|
getTotalActiveEmissionValue(chainConfig, denom),
|
||||||
getMarket(denom),
|
getMarket(chainConfig, denom),
|
||||||
])
|
])
|
||||||
|
|
||||||
if (!totalActiveEmissionValue) return null
|
if (!totalActiveEmissionValue) return null
|
||||||
|
|
||||||
const [marketLiquidityAmount, assetPrice] = await Promise.all([
|
const [marketLiquidityAmount, assetPrice] = await Promise.all([
|
||||||
getUnderlyingLiquidityAmount(market),
|
getUnderlyingLiquidityAmount(chainConfig, market),
|
||||||
getPrice(denom),
|
getPrice(chainConfig, denom),
|
||||||
])
|
])
|
||||||
|
|
||||||
const assetDecimals = (ASSETS.find(byDenom(denom)) as Asset).decimals
|
const assetDecimals = (chainConfig.assets.find(byDenom(denom)) as Asset).decimals
|
||||||
|
|
||||||
const marketLiquidityValue = BN(marketLiquidityAmount)
|
const marketLiquidityValue = BN(marketLiquidityAmount)
|
||||||
.shiftedBy(-assetDecimals)
|
.shiftedBy(-assetDecimals)
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { cacheFn, emissionsCache } from 'api/cache'
|
import { cacheFn, emissionsCache } from 'api/cache'
|
||||||
import { getIncentivesQueryClient } from 'api/cosmwasm-client'
|
import { getIncentivesQueryClient } from 'api/cosmwasm-client'
|
||||||
import getPrice from 'api/prices/getPrice'
|
import getPrice from 'api/prices/getPrice'
|
||||||
import { ASSETS } from 'constants/assets'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
export default async function getTotalActiveEmissionValue(
|
export default async function getTotalActiveEmissionValue(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
denom: string,
|
denom: string,
|
||||||
): Promise<BigNumber | null> {
|
): Promise<BigNumber | null> {
|
||||||
try {
|
try {
|
||||||
const client = await getIncentivesQueryClient()
|
const client = await getIncentivesQueryClient(chainConfig)
|
||||||
const activeEmissions = await cacheFn(
|
const activeEmissions = await cacheFn(
|
||||||
() =>
|
() =>
|
||||||
client.activeEmissions({
|
client.activeEmissions({
|
||||||
@ -26,12 +26,12 @@ export default async function getTotalActiveEmissionValue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const prices = await Promise.all(
|
const prices = await Promise.all(
|
||||||
activeEmissions.map((activeEmission) => getPrice(activeEmission.denom)),
|
activeEmissions.map((activeEmission) => getPrice(chainConfig, activeEmission.denom)),
|
||||||
)
|
)
|
||||||
|
|
||||||
return activeEmissions.reduce((accumulation, current, index) => {
|
return activeEmissions.reduce((accumulation, current, index) => {
|
||||||
const price = prices[index]
|
const price = prices[index]
|
||||||
const decimals = ASSETS.find(byDenom(current.denom))?.decimals as number
|
const decimals = chainConfig.assets.find(byDenom(current.denom))?.decimals as number
|
||||||
const emissionValue = BN(current.emission_rate).shiftedBy(-decimals).multipliedBy(price)
|
const emissionValue = BN(current.emission_rate).shiftedBy(-decimals).multipliedBy(price)
|
||||||
|
|
||||||
return accumulation.plus(emissionValue)
|
return accumulation.plus(emissionValue)
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
import { cacheFn, unclaimedRewardsCache } from 'api/cache'
|
import { cacheFn, unclaimedRewardsCache } from 'api/cache'
|
||||||
import { getIncentivesQueryClient } from 'api/cosmwasm-client'
|
import { getIncentivesQueryClient } from 'api/cosmwasm-client'
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import iterateContractQuery from 'utils/iterateContractQuery'
|
import iterateContractQuery from 'utils/iterateContractQuery'
|
||||||
|
|
||||||
export default async function getUnclaimedRewards(accountId: string): Promise<BNCoin[]> {
|
export default async function getUnclaimedRewards(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
accountId: string,
|
||||||
|
): Promise<BNCoin[]> {
|
||||||
try {
|
try {
|
||||||
const client = await getIncentivesQueryClient()
|
const client = await getIncentivesQueryClient(chainConfig)
|
||||||
const unclaimedRewards = await cacheFn(
|
const unclaimedRewards = await cacheFn(
|
||||||
() =>
|
() =>
|
||||||
iterateContractQuery(() =>
|
iterateContractQuery(() =>
|
||||||
client.userUnclaimedRewards({
|
client.userUnclaimedRewards({
|
||||||
user: ENV.ADDRESS_CREDIT_MANAGER,
|
user: chainConfig.contracts.creditManager,
|
||||||
accountId,
|
accountId,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
@ -2,14 +2,14 @@ import { cacheFn, marketCache } from 'api/cache'
|
|||||||
import { getParamsQueryClient, getRedBankQueryClient } from 'api/cosmwasm-client'
|
import { getParamsQueryClient, getRedBankQueryClient } from 'api/cosmwasm-client'
|
||||||
import { resolveMarketResponse } from 'utils/resolvers'
|
import { resolveMarketResponse } from 'utils/resolvers'
|
||||||
|
|
||||||
export default async function getMarket(denom: string): Promise<Market> {
|
export default async function getMarket(chainConfig: ChainConfig, denom: string): Promise<Market> {
|
||||||
return cacheFn(() => fetchMarket(denom), marketCache, denom, 60)
|
return cacheFn(() => fetchMarket(chainConfig, denom), marketCache, denom, 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchMarket(denom: string) {
|
async function fetchMarket(chainConfig: ChainConfig, denom: string) {
|
||||||
try {
|
try {
|
||||||
const redBankClient = await getRedBankQueryClient()
|
const redBankClient = await getRedBankQueryClient(chainConfig)
|
||||||
const paramsClient = await getParamsQueryClient()
|
const paramsClient = await getParamsQueryClient(chainConfig)
|
||||||
|
|
||||||
const [market, assetParams, assetCap] = await Promise.all([
|
const [market, assetParams, assetCap] = await Promise.all([
|
||||||
redBankClient.market({ denom }),
|
redBankClient.market({ denom }),
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
import getMarketLiquidities from 'api/markets/getMarketLiquidities'
|
import getMarketLiquidities from 'api/markets/getMarketLiquidities'
|
||||||
import getMarkets from 'api/markets/getMarkets'
|
import getMarkets from 'api/markets/getMarkets'
|
||||||
import getPrices from 'api/prices/getPrices'
|
import getPrices from 'api/prices/getPrices'
|
||||||
import { getEnabledMarketAssets } from 'utils/assets'
|
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
export default async function getMarketBorrowings(): Promise<BorrowAsset[]> {
|
export default async function getMarketBorrowings(
|
||||||
const liquidities = await getMarketLiquidities()
|
chainConfig: ChainConfig,
|
||||||
const enabledAssets = getEnabledMarketAssets()
|
): Promise<BorrowAsset[]> {
|
||||||
const borrowEnabledMarkets = (await getMarkets()).filter((market: Market) => market.borrowEnabled)
|
const liquidities = await getMarketLiquidities(chainConfig)
|
||||||
const prices = await getPrices()
|
const borrowEnabledMarkets = (await getMarkets(chainConfig)).filter(
|
||||||
|
(market: Market) => market.borrowEnabled,
|
||||||
|
)
|
||||||
|
const prices = await getPrices(chainConfig)
|
||||||
|
|
||||||
const borrow: BorrowAsset[] = borrowEnabledMarkets.map((market) => {
|
const borrow: BorrowAsset[] = borrowEnabledMarkets.map((market) => {
|
||||||
const price = prices.find((coin) => coin.denom === market.denom)?.amount ?? '1'
|
const price = prices.find((coin) => coin.denom === market.denom)?.amount ?? '1'
|
||||||
const amount = liquidities.find((coin) => coin.denom === market.denom)?.amount ?? '0'
|
const amount = liquidities.find((coin) => coin.denom === market.denom)?.amount ?? '0'
|
||||||
const asset = enabledAssets.find((asset) => asset.denom === market.denom)!
|
const asset = chainConfig.assets.find((asset) => asset.denom === market.denom)!
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...asset,
|
...asset,
|
||||||
|
@ -3,10 +3,10 @@ import { getRedBankQueryClient } from 'api/cosmwasm-client'
|
|||||||
import getMarkets from 'api/markets/getMarkets'
|
import getMarkets from 'api/markets/getMarkets'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
export default async function getMarketDebts(): Promise<BNCoin[]> {
|
export default async function getMarketDebts(chainConfig: ChainConfig): Promise<BNCoin[]> {
|
||||||
try {
|
try {
|
||||||
const markets: Market[] = await getMarkets()
|
const markets: Market[] = await getMarkets(chainConfig)
|
||||||
const redBankQueryClient = await getRedBankQueryClient()
|
const redBankQueryClient = await getRedBankQueryClient(chainConfig)
|
||||||
|
|
||||||
const debtQueries = markets.map((asset) =>
|
const debtQueries = markets.map((asset) =>
|
||||||
cacheFn(
|
cacheFn(
|
||||||
|
@ -2,10 +2,12 @@ import getMarkets from 'api/markets/getMarkets'
|
|||||||
import getUnderlyingLiquidityAmount from 'api/markets/getMarketUnderlyingLiquidityAmount'
|
import getUnderlyingLiquidityAmount from 'api/markets/getMarketUnderlyingLiquidityAmount'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
export default async function getMarketDeposits(): Promise<BNCoin[]> {
|
export default async function getMarketDeposits(chainConfig: ChainConfig): Promise<BNCoin[]> {
|
||||||
try {
|
try {
|
||||||
const markets: Market[] = await getMarkets()
|
const markets: Market[] = await getMarkets(chainConfig)
|
||||||
const depositQueries = markets.map(getUnderlyingLiquidityAmount)
|
const depositQueries = markets.map((market) =>
|
||||||
|
getUnderlyingLiquidityAmount(chainConfig, market),
|
||||||
|
)
|
||||||
const depositsResults = await Promise.all(depositQueries)
|
const depositsResults = await Promise.all(depositQueries)
|
||||||
|
|
||||||
return depositsResults.map<BNCoin>(
|
return depositsResults.map<BNCoin>(
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { BN } from 'utils/helpers'
|
|
||||||
import getMarketDeposits from 'api/markets/getMarketDeposits'
|
|
||||||
import getMarketDebts from 'api/markets/getMarketDebts'
|
import getMarketDebts from 'api/markets/getMarketDebts'
|
||||||
|
import getMarketDeposits from 'api/markets/getMarketDeposits'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
export default async function getMarketLiquidities(): Promise<BNCoin[]> {
|
export default async function getMarketLiquidities(chainConfig: ChainConfig): Promise<BNCoin[]> {
|
||||||
const deposits = await getMarketDeposits()
|
const deposits = await getMarketDeposits(chainConfig)
|
||||||
const debts = await getMarketDebts()
|
const debts = await getMarketDebts(chainConfig)
|
||||||
|
|
||||||
const liquidity: BNCoin[] = deposits.map((deposit) => {
|
const liquidity: BNCoin[] = deposits.map((deposit) => {
|
||||||
const debt = debts.find((debt) => debt.denom === deposit.denom)
|
const debt = debts.find((debt) => debt.denom === deposit.denom)
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
import { cacheFn, underlyingLiquidityAmountCache } from 'api/cache'
|
import { cacheFn, underlyingLiquidityAmountCache } from 'api/cache'
|
||||||
import { getRedBankQueryClient } from 'api/cosmwasm-client'
|
import { getRedBankQueryClient } from 'api/cosmwasm-client'
|
||||||
|
|
||||||
export default async function getUnderlyingLiquidityAmount(market: Market): Promise<string> {
|
export default async function getUnderlyingLiquidityAmount(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
market: Market,
|
||||||
|
): Promise<string> {
|
||||||
return cacheFn(
|
return cacheFn(
|
||||||
() => fetchUnderlyingLiquidityAmount(market),
|
() => fetchUnderlyingLiquidityAmount(chainConfig, market),
|
||||||
underlyingLiquidityAmountCache,
|
underlyingLiquidityAmountCache,
|
||||||
`underlyingLiquidity/${market.denom}/amount/${market.collateralTotalScaled}`,
|
`underlyingLiquidity/${market.denom}/amount/${market.collateralTotalScaled}`,
|
||||||
60,
|
60,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchUnderlyingLiquidityAmount(market: Market) {
|
async function fetchUnderlyingLiquidityAmount(chainConfig: ChainConfig, market: Market) {
|
||||||
try {
|
try {
|
||||||
const client = await getRedBankQueryClient()
|
const client = await getRedBankQueryClient(chainConfig)
|
||||||
return await client.underlyingLiquidityAmount({
|
return await client.underlyingLiquidityAmount({
|
||||||
denom: market.denom,
|
denom: market.denom,
|
||||||
amountScaled: market.collateralTotalScaled,
|
amountScaled: market.collateralTotalScaled,
|
||||||
|
@ -6,36 +6,46 @@ import {
|
|||||||
} from 'types/generated/mars-params/MarsParams.types'
|
} from 'types/generated/mars-params/MarsParams.types'
|
||||||
import { Market as RedBankMarket } from 'types/generated/mars-red-bank/MarsRedBank.types'
|
import { Market as RedBankMarket } from 'types/generated/mars-red-bank/MarsRedBank.types'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { getEnabledMarketAssets } from 'utils/assets'
|
|
||||||
import iterateContractQuery from 'utils/iterateContractQuery'
|
import iterateContractQuery from 'utils/iterateContractQuery'
|
||||||
import { resolveMarketResponse } from 'utils/resolvers'
|
import { resolveMarketResponse } from 'utils/resolvers'
|
||||||
|
|
||||||
export default async function getMarkets(): Promise<Market[]> {
|
export default async function getMarkets(chainConfig: ChainConfig): Promise<Market[]> {
|
||||||
try {
|
try {
|
||||||
const redBankClient = await getRedBankQueryClient()
|
const redBankClient = await getRedBankQueryClient(chainConfig)
|
||||||
const paramsClient = await getParamsQueryClient()
|
const paramsClient = await getParamsQueryClient(chainConfig)
|
||||||
|
|
||||||
const enabledAssets = getEnabledMarketAssets()
|
const marketAssets = chainConfig.assets.filter((asset) => asset.isMarket)
|
||||||
const capQueries = enabledAssets.map((asset) =>
|
|
||||||
|
const capQueries = marketAssets
|
||||||
|
.filter((asset) => asset.isMarket)
|
||||||
|
.map((asset) =>
|
||||||
|
cacheFn(
|
||||||
|
() => paramsClient.totalDeposit({ denom: asset.denom }),
|
||||||
|
totalDepositCache,
|
||||||
|
`chains/${chainConfig.id}/enabledMarkets/${asset.denom}`,
|
||||||
|
60,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
const caps = await Promise.all(capQueries)
|
||||||
|
|
||||||
|
const [markets, assetParams, assetCaps] = await Promise.all([
|
||||||
cacheFn(
|
cacheFn(
|
||||||
() => paramsClient.totalDeposit({ denom: asset.denom }),
|
() => iterateContractQuery(redBankClient.markets),
|
||||||
totalDepositCache,
|
marketsCache,
|
||||||
`enabledMarkets/${asset.denom}`,
|
`chains/${chainConfig.id}/markets`,
|
||||||
60,
|
60,
|
||||||
),
|
),
|
||||||
)
|
|
||||||
const [markets, assetParams, assetCaps] = await Promise.all([
|
|
||||||
cacheFn(() => iterateContractQuery(redBankClient.markets), marketsCache, 'markets', 60),
|
|
||||||
cacheFn(
|
cacheFn(
|
||||||
async () => await iterateContractQuery(paramsClient.allAssetParams),
|
async () => await iterateContractQuery(paramsClient.allAssetParams),
|
||||||
allParamsCache,
|
allParamsCache,
|
||||||
'params',
|
`chains/${chainConfig.id}/params`,
|
||||||
60,
|
60,
|
||||||
),
|
),
|
||||||
Promise.all(capQueries),
|
Promise.all(capQueries),
|
||||||
])
|
])
|
||||||
|
|
||||||
return enabledAssets.map((asset) =>
|
return marketAssets.map((asset) =>
|
||||||
resolveMarketResponse(
|
resolveMarketResponse(
|
||||||
markets.find(byDenom(asset.denom)) as RedBankMarket,
|
markets.find(byDenom(asset.denom)) as RedBankMarket,
|
||||||
assetParams.find(byDenom(asset.denom)) as AssetParams,
|
assetParams.find(byDenom(asset.denom)) as AssetParams,
|
||||||
@ -43,6 +53,7 @@ export default async function getMarkets(): Promise<Market[]> {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
console.log(ex)
|
||||||
throw ex
|
throw ex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,13 @@ import { getParamsQueryClient } from 'api/cosmwasm-client'
|
|||||||
import { AssetParamsBaseForAddr } from 'types/generated/mars-params/MarsParams.types'
|
import { AssetParamsBaseForAddr } from 'types/generated/mars-params/MarsParams.types'
|
||||||
import iterateContractQuery from 'utils/iterateContractQuery'
|
import iterateContractQuery from 'utils/iterateContractQuery'
|
||||||
|
|
||||||
export default async function getAssetParams(): Promise<AssetParamsBaseForAddr[]> {
|
export default async function getAssetParams(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
): Promise<AssetParamsBaseForAddr[]> {
|
||||||
try {
|
try {
|
||||||
return await cacheFn(
|
return await cacheFn(
|
||||||
async () => {
|
async () => {
|
||||||
const paramsQueryClient = await getParamsQueryClient()
|
const paramsQueryClient = await getParamsQueryClient(chainConfig)
|
||||||
return iterateContractQuery(paramsQueryClient.allAssetParams)
|
return iterateContractQuery(paramsQueryClient.allAssetParams)
|
||||||
},
|
},
|
||||||
assetParamsCache,
|
assetParamsCache,
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import getPoolPrice from 'api/prices/getPoolPrice'
|
import getPoolPrice from 'api/prices/getPoolPrice'
|
||||||
import { ASSETS } from 'constants/assets'
|
|
||||||
import { bySymbol } from 'utils/array'
|
import { bySymbol } from 'utils/array'
|
||||||
|
|
||||||
async function getMarsPrice() {
|
async function getMarsPrice(chainConfig: ChainConfig) {
|
||||||
const marsAsset = ASSETS.find(bySymbol('MARS'))
|
const marsAsset = chainConfig.assets.find(bySymbol('MARS'))
|
||||||
if (!marsAsset) return 0
|
if (!marsAsset) return 0
|
||||||
return await getPoolPrice(marsAsset)
|
return await getPoolPrice(chainConfig, marsAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default getMarsPrice
|
export default getMarsPrice
|
||||||
|
@ -7,11 +7,14 @@ import { byDenom } from 'utils/array'
|
|||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import iterateContractQuery from 'utils/iterateContractQuery'
|
import iterateContractQuery from 'utils/iterateContractQuery'
|
||||||
|
|
||||||
export default async function getOraclePrices(...assets: Asset[]): Promise<BNCoin[]> {
|
export default async function getOraclePrices(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
assets: Asset[],
|
||||||
|
): Promise<BNCoin[]> {
|
||||||
try {
|
try {
|
||||||
if (!assets.length) return []
|
if (!assets.length) return []
|
||||||
|
|
||||||
const oracleQueryClient = await getOracleQueryClient()
|
const oracleQueryClient = await getOracleQueryClient(chainConfig)
|
||||||
const priceResults = await cacheFn(
|
const priceResults = await cacheFn(
|
||||||
() => iterateContractQuery(oracleQueryClient.prices),
|
() => iterateContractQuery(oracleQueryClient.prices),
|
||||||
oraclePriceCache,
|
oraclePriceCache,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { cacheFn, poolPriceCache } from 'api/cache'
|
import { cacheFn, poolPriceCache } from 'api/cache'
|
||||||
import getPrice from 'api/prices/getPrice'
|
import getPrice from 'api/prices/getPrice'
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
import { BN_ONE } from 'constants/math'
|
import { BN_ONE } from 'constants/math'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { byDenom, byTokenDenom, partition } from 'utils/array'
|
import { byDenom, byTokenDenom, partition } from 'utils/array'
|
||||||
@ -17,24 +16,25 @@ interface PoolAsset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function getPoolPrice(
|
export default async function getPoolPrice(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
asset: Asset,
|
asset: Asset,
|
||||||
lookupPricesForBaseAsset?: BNCoin[],
|
lookupPricesForBaseAsset?: BNCoin[],
|
||||||
): Promise<BigNumber> {
|
): Promise<BigNumber> {
|
||||||
if (!asset.poolId) throw 'given asset should have a poolId to fetch the price'
|
if (!asset.poolId) throw 'given asset should have a poolId to fetch the price'
|
||||||
|
|
||||||
const [assetRate, baseAsset] = await getAssetRate(asset)
|
const [assetRate, baseAsset] = await getAssetRate(chainConfig, asset)
|
||||||
const baseAssetPrice =
|
const baseAssetPrice =
|
||||||
(lookupPricesForBaseAsset &&
|
(lookupPricesForBaseAsset &&
|
||||||
lookupPricesForBaseAsset.find(byDenom(baseAsset.token.denom))?.amount) ||
|
lookupPricesForBaseAsset.find(byDenom(baseAsset.token.denom))?.amount) ||
|
||||||
(await getPrice(baseAsset.token.denom))
|
(await getPrice(chainConfig, baseAsset.token.denom))
|
||||||
|
|
||||||
if (!baseAssetPrice) throw 'base asset price must be available on Pyth or in Oracle contract'
|
if (!baseAssetPrice) throw 'base asset price must be available on Pyth or in Oracle contract'
|
||||||
|
|
||||||
return assetRate.multipliedBy(baseAssetPrice)
|
return assetRate.multipliedBy(baseAssetPrice)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAssetRate = async (asset: Asset) => {
|
const getAssetRate = async (chainConfig: ChainConfig, asset: Asset) => {
|
||||||
const url = `${ENV.URL_REST}osmosis/gamm/v1beta1/pools/${asset.poolId}`
|
const url = chainConfig.endpoints.pools.replace('POOL_ID', asset.poolId!.toString())
|
||||||
const response = await cacheFn(
|
const response = await cacheFn(
|
||||||
() => fetch(url).then((res) => res.json()),
|
() => fetch(url).then((res) => res.json()),
|
||||||
poolPriceCache,
|
poolPriceCache,
|
||||||
|
@ -2,25 +2,27 @@ import { cacheFn, priceCache } from 'api/cache'
|
|||||||
import { getOracleQueryClient } from 'api/cosmwasm-client'
|
import { getOracleQueryClient } from 'api/cosmwasm-client'
|
||||||
import getPoolPrice from 'api/prices/getPoolPrice'
|
import getPoolPrice from 'api/prices/getPoolPrice'
|
||||||
import getPythPrice from 'api/prices/getPythPrices'
|
import getPythPrice from 'api/prices/getPythPrices'
|
||||||
import { ASSETS } from 'constants/assets'
|
|
||||||
import { PRICE_ORACLE_DECIMALS } from 'constants/query'
|
import { PRICE_ORACLE_DECIMALS } from 'constants/query'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
export default async function getPrice(denom: string): Promise<BigNumber> {
|
export default async function getPrice(
|
||||||
return cacheFn(() => fetchPrice(denom), priceCache, `price/${denom}`, 60)
|
chainConfig: ChainConfig,
|
||||||
|
denom: string,
|
||||||
|
): Promise<BigNumber> {
|
||||||
|
return cacheFn(() => fetchPrice(chainConfig, denom), priceCache, `price/${denom}`, 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchPrice(denom: string) {
|
async function fetchPrice(chainConfig: ChainConfig, denom: string) {
|
||||||
try {
|
try {
|
||||||
const asset = ASSETS.find(byDenom(denom)) as Asset
|
const asset = chainConfig.assets.find(byDenom(denom)) as Asset
|
||||||
|
|
||||||
if (asset.pythPriceFeedId) {
|
if (asset.pythPriceFeedId) {
|
||||||
return (await getPythPrice(asset.pythPriceFeedId))[0]
|
return (await getPythPrice(chainConfig, [asset.pythPriceFeedId]))[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset.hasOraclePrice) {
|
if (asset.hasOraclePrice) {
|
||||||
const oracleQueryClient = await getOracleQueryClient()
|
const oracleQueryClient = await getOracleQueryClient(chainConfig)
|
||||||
const priceResponse = await oracleQueryClient.price({ denom: asset.denom })
|
const priceResponse = await oracleQueryClient.price({ denom: asset.denom })
|
||||||
const decimalDiff = asset.decimals - PRICE_ORACLE_DECIMALS
|
const decimalDiff = asset.decimals - PRICE_ORACLE_DECIMALS
|
||||||
|
|
||||||
@ -28,7 +30,7 @@ async function fetchPrice(denom: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (asset.poolId) {
|
if (asset.poolId) {
|
||||||
return await getPoolPrice(asset)
|
return await getPoolPrice(chainConfig, asset)
|
||||||
}
|
}
|
||||||
|
|
||||||
throw `could not fetch the price info for the given denom: ${denom}`
|
throw `could not fetch the price info for the given denom: ${denom}`
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
import fetchPythPriceData from 'api/prices/getPythPriceData'
|
import fetchPythPriceData from 'api/prices/getPythPriceData'
|
||||||
import { getPythAssets } from 'utils/assets'
|
|
||||||
|
|
||||||
export default async function getPricesData(): Promise<string[]> {
|
export default async function getPricesData(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
assets: Asset[],
|
||||||
|
): Promise<string[]> {
|
||||||
try {
|
try {
|
||||||
const assetsWithPythPriceFeedId = getPythAssets()
|
const assetsWithPythPriceFeedId = assets.filter((asset) => !!asset.pythPriceFeedId)
|
||||||
const pythAndOraclePriceData = await requestPythPriceData(assetsWithPythPriceFeedId)
|
return await requestPythPriceData(chainConfig, assetsWithPythPriceFeedId)
|
||||||
return pythAndOraclePriceData
|
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.error(ex)
|
console.error(ex)
|
||||||
throw ex
|
throw ex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function requestPythPriceData(assets: Asset[]): Promise<string[]> {
|
async function requestPythPriceData(chainConfig: ChainConfig, assets: Asset[]): Promise<string[]> {
|
||||||
if (!assets.length) return []
|
if (!assets.length) return []
|
||||||
|
|
||||||
const priceFeedIds = assets.map((a) => a.pythPriceFeedId) as string[]
|
const priceFeedIds = assets.map((a) => a.pythPriceFeedId) as string[]
|
||||||
return await fetchPythPriceData(...priceFeedIds)
|
return await fetchPythPriceData(chainConfig, priceFeedIds)
|
||||||
}
|
}
|
||||||
|
@ -4,22 +4,25 @@ import fetchPythPrices from 'api/prices/getPythPrices'
|
|||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { partition } from 'utils/array'
|
import { partition } from 'utils/array'
|
||||||
import { getAssetsMustHavePriceInfo } from 'utils/assets'
|
|
||||||
|
|
||||||
export default async function getPrices(): Promise<BNCoin[]> {
|
export default async function getPrices(chainConfig: ChainConfig): Promise<BNCoin[]> {
|
||||||
const usdPrice = new BNCoin({ denom: 'usd', amount: '1' })
|
const usdPrice = new BNCoin({ denom: 'usd', amount: '1' })
|
||||||
try {
|
try {
|
||||||
const assetsToFetchPrices = getAssetsMustHavePriceInfo()
|
const assetsToFetchPrices = useStore
|
||||||
|
.getState()
|
||||||
|
.chainConfig.assets.filter(
|
||||||
|
(asset) => (asset.isEnabled && asset.isMarket) || asset.forceFetchPrice,
|
||||||
|
)
|
||||||
const [assetsWithPythPriceFeedId, assetsWithOraclePrices, assetsWithPoolIds] =
|
const [assetsWithPythPriceFeedId, assetsWithOraclePrices, assetsWithPoolIds] =
|
||||||
separateAssetsByPriceSources(assetsToFetchPrices)
|
separateAssetsByPriceSources(assetsToFetchPrices)
|
||||||
|
|
||||||
const pythAndOraclePrices = (
|
const pythAndOraclePrices = (
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
requestPythPrices(assetsWithPythPriceFeedId),
|
requestPythPrices(chainConfig, assetsWithPythPriceFeedId),
|
||||||
getOraclePrices(...assetsWithOraclePrices),
|
getOraclePrices(chainConfig, assetsWithOraclePrices),
|
||||||
])
|
])
|
||||||
).flat()
|
).flat()
|
||||||
const poolPrices = await requestPoolPrices(assetsWithPoolIds, pythAndOraclePrices)
|
const poolPrices = await requestPoolPrices(chainConfig, assetsWithPoolIds, pythAndOraclePrices)
|
||||||
|
|
||||||
useStore.setState({ isOracleStale: false })
|
useStore.setState({ isOracleStale: false })
|
||||||
|
|
||||||
@ -35,15 +38,19 @@ export default async function getPrices(): Promise<BNCoin[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function requestPythPrices(assets: Asset[]): Promise<BNCoin[]> {
|
async function requestPythPrices(chainConfig: ChainConfig, assets: Asset[]): Promise<BNCoin[]> {
|
||||||
if (!assets.length) return []
|
if (!assets.length) return []
|
||||||
|
|
||||||
const priceFeedIds = assets.map((a) => a.pythPriceFeedId) as string[]
|
const priceFeedIds = assets.map((a) => a.pythPriceFeedId) as string[]
|
||||||
return await fetchPythPrices(...priceFeedIds).then(mapResponseToBnCoin(assets))
|
return await fetchPythPrices(chainConfig, priceFeedIds).then(mapResponseToBnCoin(assets))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function requestPoolPrices(assets: Asset[], lookupPrices: BNCoin[]): Promise<BNCoin[]> {
|
async function requestPoolPrices(
|
||||||
const requests = assets.map((asset) => getPoolPrice(asset, lookupPrices))
|
chainConfig: ChainConfig,
|
||||||
|
assets: Asset[],
|
||||||
|
lookupPrices: BNCoin[],
|
||||||
|
): Promise<BNCoin[]> {
|
||||||
|
const requests = assets.map((asset) => getPoolPrice(chainConfig, asset, lookupPrices))
|
||||||
|
|
||||||
return await Promise.all(requests).then(mapResponseToBnCoin(assets))
|
return await Promise.all(requests).then(mapResponseToBnCoin(assets))
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { cacheFn, pythPriceCache } from 'api/cache'
|
import { cacheFn, pythPriceCache } from 'api/cache'
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
|
|
||||||
export default async function fetchPythPriceData(...priceFeedIds: string[]) {
|
export default async function fetchPythPriceData(chainConfig: ChainConfig, priceFeedIds: string[]) {
|
||||||
try {
|
try {
|
||||||
const pricesUrl = new URL(`${ENV.PYTH_ENDPOINT}/latest_vaas`)
|
const pricesUrl = new URL(`${chainConfig.endpoints.pyth}/latest_vaas`)
|
||||||
priceFeedIds.forEach((id) => pricesUrl.searchParams.append('ids[]', id))
|
priceFeedIds.forEach((id) => pricesUrl.searchParams.append('ids[]', id))
|
||||||
|
|
||||||
const pythDataResponse: string[] = await cacheFn(
|
const pythDataResponse: string[] = await cacheFn(
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { cacheFn, pythPriceCache } from 'api/cache'
|
import { cacheFn, pythPriceCache } from 'api/cache'
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
export default async function fetchPythPrices(...priceFeedIds: string[]) {
|
export default async function fetchPythPrices(chainConfig: ChainConfig, priceFeedIds: string[]) {
|
||||||
try {
|
try {
|
||||||
const pricesUrl = new URL(`${ENV.PYTH_ENDPOINT}/latest_price_feeds`)
|
const pricesUrl = new URL(`${chainConfig.endpoints.pyth}/latest_price_feeds`)
|
||||||
priceFeedIds.forEach((id) => pricesUrl.searchParams.append('ids[]', id))
|
priceFeedIds.forEach((id) => pricesUrl.searchParams.append('ids[]', id))
|
||||||
|
|
||||||
const pythResponse: PythPriceData[] = await cacheFn(
|
const pythResponse: PythPriceData[] = await cacheFn(
|
||||||
|
@ -2,9 +2,13 @@ import { getSwapperQueryClient } from 'api/cosmwasm-client'
|
|||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
export default async function estimateExactIn(coinIn: Coin, denomOut: string) {
|
export default async function estimateExactIn(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
coinIn: Coin,
|
||||||
|
denomOut: string,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const swapperClient = await getSwapperQueryClient()
|
const swapperClient = await getSwapperQueryClient(chainConfig)
|
||||||
const estimatedAmount = (await swapperClient.estimateExactInSwap({ coinIn, denomOut })).amount
|
const estimatedAmount = (await swapperClient.estimateExactInSwap({ coinIn, denomOut })).amount
|
||||||
|
|
||||||
return BN(estimatedAmount)
|
return BN(estimatedAmount)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { ENV } from 'constants/env'
|
export default async function getPools(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
const url = `${ENV.URL_REST}osmosis/gamm/v1beta1/pools/`
|
poolIds: string[],
|
||||||
export default async function getPools(poolIds: string[]): Promise<Pool[]> {
|
): Promise<Pool[]> {
|
||||||
const promises = poolIds.map((poolId) => fetch(url + poolId))
|
const promises = poolIds.map((poolId) =>
|
||||||
|
fetch(chainConfig.endpoints.pools.replace('POOL_ID', poolId)),
|
||||||
|
)
|
||||||
|
|
||||||
const responses = await Promise.all(promises)
|
const responses = await Promise.all(promises)
|
||||||
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import { getSwapperQueryClient } from 'api/cosmwasm-client'
|
import { getSwapperQueryClient } from 'api/cosmwasm-client'
|
||||||
|
|
||||||
export default async function getSwapRoute(denomIn: string, denomOut: string): Promise<Route[]> {
|
export default async function getSwapRoute(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
denomIn: string,
|
||||||
|
denomOut: string,
|
||||||
|
): Promise<Route[]> {
|
||||||
try {
|
try {
|
||||||
const swapperClient = await getSwapperQueryClient()
|
const swapperClient = await getSwapperQueryClient(chainConfig)
|
||||||
const routes = await swapperClient.route({
|
const routes = await swapperClient.route({
|
||||||
denomIn,
|
denomIn,
|
||||||
denomOut,
|
denomOut,
|
||||||
|
@ -21,9 +21,13 @@ import {
|
|||||||
import { getCoinValue } from 'utils/formatters'
|
import { getCoinValue } from 'utils/formatters'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
async function getUnlocksAtTimestamp(unlockingId: number, vaultAddress: string) {
|
async function getUnlocksAtTimestamp(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
unlockingId: number,
|
||||||
|
vaultAddress: string,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const client = await getClient()
|
const client = await getClient(chainConfig.endpoints.rpc)
|
||||||
|
|
||||||
const vaultExtension = (await cacheFn(
|
const vaultExtension = (await cacheFn(
|
||||||
() =>
|
() =>
|
||||||
@ -42,6 +46,7 @@ async function getUnlocksAtTimestamp(unlockingId: number, vaultAddress: string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getVaultPositionStatusAndUnlockIdAndUnlockTime(
|
async function getVaultPositionStatusAndUnlockIdAndUnlockTime(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
vaultPosition: VaultPosition,
|
vaultPosition: VaultPosition,
|
||||||
): Promise<[VaultStatus, number | undefined, number | undefined]> {
|
): Promise<[VaultStatus, number | undefined, number | undefined]> {
|
||||||
const amount = vaultPosition.amount
|
const amount = vaultPosition.amount
|
||||||
@ -50,7 +55,11 @@ async function getVaultPositionStatusAndUnlockIdAndUnlockTime(
|
|||||||
|
|
||||||
if (amount.locking.unlocking.length) {
|
if (amount.locking.unlocking.length) {
|
||||||
const unlockId = amount.locking.unlocking[0].id
|
const unlockId = amount.locking.unlocking[0].id
|
||||||
const unlocksAtTimestamp = await getUnlocksAtTimestamp(unlockId, vaultPosition.vault.address)
|
const unlocksAtTimestamp = await getUnlocksAtTimestamp(
|
||||||
|
chainConfig,
|
||||||
|
unlockId,
|
||||||
|
vaultPosition.vault.address,
|
||||||
|
)
|
||||||
|
|
||||||
if (moment(unlocksAtTimestamp).isBefore(new Date())) {
|
if (moment(unlocksAtTimestamp).isBefore(new Date())) {
|
||||||
return [VaultStatus.UNLOCKED, unlockId, unlocksAtTimestamp]
|
return [VaultStatus.UNLOCKED, unlockId, unlocksAtTimestamp]
|
||||||
@ -83,12 +92,13 @@ export function flatVaultPositionAmount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getLpTokensForVaultPosition(
|
export async function getLpTokensForVaultPosition(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
vault: Vault,
|
vault: Vault,
|
||||||
vaultPosition: VaultPosition,
|
vaultPosition: VaultPosition,
|
||||||
): Promise<Coin[]> {
|
): Promise<Coin[]> {
|
||||||
try {
|
try {
|
||||||
const vaultQueryClient = await getVaultQueryClient(vault.address)
|
const vaultQueryClient = await getVaultQueryClient(chainConfig, vault.address)
|
||||||
const creditManagerQueryClient = await getCreditManagerQueryClient()
|
const creditManagerQueryClient = await getCreditManagerQueryClient(chainConfig)
|
||||||
const amounts = flatVaultPositionAmount(vaultPosition.amount)
|
const amounts = flatVaultPositionAmount(vaultPosition.amount)
|
||||||
const totalAmount = amounts.locked.plus(amounts.unlocked).plus(amounts.unlocking).toString()
|
const totalAmount = amounts.locked.plus(amounts.unlocked).plus(amounts.unlocking).toString()
|
||||||
|
|
||||||
@ -133,15 +143,16 @@ export async function getLpTokensForVaultPosition(
|
|||||||
async function getVaultValuesAndAmounts(
|
async function getVaultValuesAndAmounts(
|
||||||
vault: Vault,
|
vault: Vault,
|
||||||
vaultPosition: VaultPosition,
|
vaultPosition: VaultPosition,
|
||||||
|
chainConfig: ChainConfig,
|
||||||
): Promise<VaultValuesAndAmounts> {
|
): Promise<VaultValuesAndAmounts> {
|
||||||
try {
|
try {
|
||||||
const pricesQueries = Promise.all([
|
const pricesQueries = Promise.all([
|
||||||
getPrice(vault.denoms.primary),
|
getPrice(chainConfig, vault.denoms.primary),
|
||||||
getPrice(vault.denoms.secondary),
|
getPrice(chainConfig, vault.denoms.secondary),
|
||||||
getPrice(vault.denoms.lp),
|
getPrice(chainConfig, vault.denoms.lp),
|
||||||
])
|
])
|
||||||
|
|
||||||
const lpTokensQuery = getLpTokensForVaultPosition(vault, vaultPosition)
|
const lpTokensQuery = getLpTokensForVaultPosition(chainConfig, vault, vaultPosition)
|
||||||
const amounts = flatVaultPositionAmount(vaultPosition.amount)
|
const amounts = flatVaultPositionAmount(vaultPosition.amount)
|
||||||
|
|
||||||
const [[primaryLpToken, secondaryLpToken], [primaryPrice, secondaryPrice, lpPrice]] =
|
const [[primaryLpToken, secondaryLpToken], [primaryPrice, secondaryPrice, lpPrice]] =
|
||||||
@ -154,18 +165,26 @@ async function getVaultValuesAndAmounts(
|
|||||||
secondary: BN(secondaryLpToken.amount),
|
secondary: BN(secondaryLpToken.amount),
|
||||||
},
|
},
|
||||||
values: {
|
values: {
|
||||||
primary: getCoinValue(new BNCoin(primaryLpToken), [
|
primary: getCoinValue(
|
||||||
BNCoin.fromDenomAndBigNumber(primaryLpToken.denom, primaryPrice),
|
new BNCoin(primaryLpToken),
|
||||||
]),
|
[BNCoin.fromDenomAndBigNumber(primaryLpToken.denom, primaryPrice)],
|
||||||
secondary: getCoinValue(new BNCoin(secondaryLpToken), [
|
chainConfig.assets,
|
||||||
BNCoin.fromDenomAndBigNumber(secondaryLpToken.denom, secondaryPrice),
|
),
|
||||||
]),
|
secondary: getCoinValue(
|
||||||
unlocking: getCoinValue(BNCoin.fromDenomAndBigNumber(vault.denoms.lp, amounts.unlocking), [
|
new BNCoin(secondaryLpToken),
|
||||||
BNCoin.fromDenomAndBigNumber(vault.denoms.lp, lpPrice),
|
[BNCoin.fromDenomAndBigNumber(secondaryLpToken.denom, secondaryPrice)],
|
||||||
]),
|
chainConfig.assets,
|
||||||
unlocked: getCoinValue(BNCoin.fromDenomAndBigNumber(vault.denoms.lp, amounts.unlocked), [
|
),
|
||||||
BNCoin.fromDenomAndBigNumber(vault.denoms.lp, lpPrice),
|
unlocking: getCoinValue(
|
||||||
]),
|
BNCoin.fromDenomAndBigNumber(vault.denoms.lp, amounts.unlocking),
|
||||||
|
[BNCoin.fromDenomAndBigNumber(vault.denoms.lp, lpPrice)],
|
||||||
|
chainConfig.assets,
|
||||||
|
),
|
||||||
|
unlocked: getCoinValue(
|
||||||
|
BNCoin.fromDenomAndBigNumber(vault.denoms.lp, amounts.unlocked),
|
||||||
|
[BNCoin.fromDenomAndBigNumber(vault.denoms.lp, lpPrice)],
|
||||||
|
chainConfig.assets,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
@ -175,10 +194,11 @@ async function getVaultValuesAndAmounts(
|
|||||||
|
|
||||||
async function getDepositedVaults(
|
async function getDepositedVaults(
|
||||||
accountId: string,
|
accountId: string,
|
||||||
|
chainConfig: ChainConfig,
|
||||||
positions?: Positions,
|
positions?: Positions,
|
||||||
): Promise<DepositedVault[]> {
|
): Promise<DepositedVault[]> {
|
||||||
try {
|
try {
|
||||||
const creditManagerQueryClient = await getCreditManagerQueryClient()
|
const creditManagerQueryClient = await getCreditManagerQueryClient(chainConfig)
|
||||||
|
|
||||||
if (!positions)
|
if (!positions)
|
||||||
positions = await cacheFn(
|
positions = await cacheFn(
|
||||||
@ -189,7 +209,7 @@ async function getDepositedVaults(
|
|||||||
|
|
||||||
if (!positions.vaults.length) return []
|
if (!positions.vaults.length) return []
|
||||||
|
|
||||||
const [allVaults] = await Promise.all([getVaults()])
|
const [allVaults] = await Promise.all([getVaults(chainConfig)])
|
||||||
|
|
||||||
const depositedVaults = positions.vaults.map(async (vaultPosition) => {
|
const depositedVaults = positions.vaults.map(async (vaultPosition) => {
|
||||||
const vault = allVaults.find((v) => v.address === vaultPosition.vault.address)
|
const vault = allVaults.find((v) => v.address === vaultPosition.vault.address)
|
||||||
@ -199,8 +219,8 @@ async function getDepositedVaults(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [[status, unlockId, unlocksAt], valuesAndAmounts] = await Promise.all([
|
const [[status, unlockId, unlocksAt], valuesAndAmounts] = await Promise.all([
|
||||||
getVaultPositionStatusAndUnlockIdAndUnlockTime(vaultPosition),
|
getVaultPositionStatusAndUnlockIdAndUnlockTime(chainConfig, vaultPosition),
|
||||||
getVaultValuesAndAmounts(vault, vaultPosition),
|
getVaultValuesAndAmounts(vault, vaultPosition, chainConfig),
|
||||||
])
|
])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { aprsCache, aprsCacheResponse, cacheFn } from 'api/cache'
|
import { aprsCache, aprsCacheResponse, cacheFn } from 'api/cache'
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
|
|
||||||
export default async function getAprs() {
|
export default async function getAprs(chainConfig: ChainConfig) {
|
||||||
try {
|
try {
|
||||||
const response = await cacheFn(
|
const response = await cacheFn(
|
||||||
() => fetch(ENV.URL_VAULT_APR),
|
() => fetch(chainConfig.endpoints.aprs.vaults),
|
||||||
aprsCacheResponse,
|
aprsCacheResponse,
|
||||||
'aprsResponse',
|
'aprsResponse',
|
||||||
60,
|
60,
|
||||||
|
@ -3,9 +3,11 @@ import { getParamsQueryClient } from 'api/cosmwasm-client'
|
|||||||
import { VaultConfigBaseForAddr } from 'types/generated/mars-params/MarsParams.types'
|
import { VaultConfigBaseForAddr } from 'types/generated/mars-params/MarsParams.types'
|
||||||
import iterateContractQuery from 'utils/iterateContractQuery'
|
import iterateContractQuery from 'utils/iterateContractQuery'
|
||||||
|
|
||||||
export const getVaultConfigs = async (): Promise<VaultConfigBaseForAddr[]> => {
|
export const getVaultConfigs = async (
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
): Promise<VaultConfigBaseForAddr[]> => {
|
||||||
try {
|
try {
|
||||||
const paramsQueryClient = await getParamsQueryClient()
|
const paramsQueryClient = await getParamsQueryClient(chainConfig)
|
||||||
return await cacheFn(
|
return await cacheFn(
|
||||||
() => iterateContractQuery(paramsQueryClient.allVaultConfigs, 'addr'),
|
() => iterateContractQuery(paramsQueryClient.allVaultConfigs, 'addr'),
|
||||||
vaultConfigsCache,
|
vaultConfigsCache,
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
import { cacheFn, previewDepositCache } from 'api/cache'
|
|
||||||
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 cacheFn(
|
|
||||||
() =>
|
|
||||||
client.previewDeposit({ amount: lpAmount }).then((amount) => ({ vaultAddress, amount })),
|
|
||||||
previewDepositCache,
|
|
||||||
`vaults/${vaultAddress}/amounts/${lpAmount}`,
|
|
||||||
30,
|
|
||||||
)
|
|
||||||
} catch (ex) {
|
|
||||||
throw ex
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +1,13 @@
|
|||||||
import { cacheFn, vaultUtilizationCache } from 'api/cache'
|
import { cacheFn, vaultUtilizationCache } from 'api/cache'
|
||||||
import { getCreditManagerQueryClient } from 'api/cosmwasm-client'
|
import { getCreditManagerQueryClient } from 'api/cosmwasm-client'
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
import { VaultUtilizationResponse } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
import { VaultUtilizationResponse } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||||
import { VaultConfigBaseForString } from 'types/generated/mars-params/MarsParams.types'
|
import { VaultConfigBaseForString } from 'types/generated/mars-params/MarsParams.types'
|
||||||
|
|
||||||
export const getVaultUtilizations = async (
|
export const getVaultUtilizations = async (
|
||||||
|
chainConfig: ChainConfig,
|
||||||
vaultConfigs: VaultConfigBaseForString[],
|
vaultConfigs: VaultConfigBaseForString[],
|
||||||
): Promise<VaultUtilizationResponse[]> => {
|
): Promise<VaultUtilizationResponse[]> => {
|
||||||
if (!ENV.ADDRESS_PARAMS) return []
|
const creditManagerQueryClient = await getCreditManagerQueryClient(chainConfig)
|
||||||
const creditManagerQueryClient = await getCreditManagerQueryClient()
|
|
||||||
try {
|
try {
|
||||||
const vaultUtilizations$ = vaultConfigs.map((vaultConfig) => {
|
const vaultUtilizations$ = vaultConfigs.map((vaultConfig) => {
|
||||||
return cacheFn(
|
return cacheFn(
|
||||||
|
@ -2,20 +2,16 @@ import getAssetParams from 'api/params/getAssetParams'
|
|||||||
import getAprs from 'api/vaults/getVaultAprs'
|
import getAprs from 'api/vaults/getVaultAprs'
|
||||||
import { getVaultConfigs } from 'api/vaults/getVaultConfigs'
|
import { getVaultConfigs } from 'api/vaults/getVaultConfigs'
|
||||||
import { getVaultUtilizations } from 'api/vaults/getVaultUtilizations'
|
import { getVaultUtilizations } from 'api/vaults/getVaultUtilizations'
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults'
|
|
||||||
import { NETWORK } from 'types/enums/network'
|
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import { convertAprToApy } from 'utils/parsers'
|
import { convertAprToApy } from 'utils/parsers'
|
||||||
import { resolveHLSStrategies } from 'utils/resolvers'
|
import { resolveHLSStrategies } from 'utils/resolvers'
|
||||||
|
|
||||||
export default async function getVaults(): Promise<Vault[]> {
|
export default async function getVaults(chainConfig: ChainConfig): Promise<Vault[]> {
|
||||||
const assetParams = await getAssetParams()
|
const assetParams = await getAssetParams(chainConfig)
|
||||||
const vaultConfigs = await getVaultConfigs()
|
const vaultConfigs = await getVaultConfigs(chainConfig)
|
||||||
const $vaultUtilizations = getVaultUtilizations(vaultConfigs)
|
const $vaultUtilizations = getVaultUtilizations(chainConfig, vaultConfigs)
|
||||||
const $aprs = getAprs()
|
const $aprs = getAprs(chainConfig)
|
||||||
const vaultMetaDatas =
|
const vaultMetaDatas = chainConfig.vaults
|
||||||
ENV.NETWORK === NETWORK.TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
|
|
||||||
const HLSAssets = assetParams.filter((asset) => asset.credit_manager.hls)
|
const HLSAssets = assetParams.filter((asset) => asset.credit_manager.hls)
|
||||||
const hlsStrategies = resolveHLSStrategies('vault', HLSAssets)
|
const hlsStrategies = resolveHLSStrategies('vault', HLSAssets)
|
||||||
|
|
||||||
|
@ -2,12 +2,13 @@ import { getCreditManagerQueryClient } from 'api/cosmwasm-client'
|
|||||||
import { ITEM_LIMIT_PER_QUERY } from 'constants/query'
|
import { ITEM_LIMIT_PER_QUERY } from 'constants/query'
|
||||||
|
|
||||||
export default async function getAccountIds(
|
export default async function getAccountIds(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
address?: string,
|
address?: string,
|
||||||
previousResults?: AccountIdAndKind[],
|
previousResults?: AccountIdAndKind[],
|
||||||
): Promise<AccountIdAndKind[]> {
|
): Promise<AccountIdAndKind[]> {
|
||||||
if (!address) return []
|
if (!address) return []
|
||||||
try {
|
try {
|
||||||
const client = await getCreditManagerQueryClient()
|
const client = await getCreditManagerQueryClient(chainConfig)
|
||||||
|
|
||||||
const lastItem = previousResults && previousResults.at(-1)
|
const lastItem = previousResults && previousResults.at(-1)
|
||||||
const accounts = (
|
const accounts = (
|
||||||
@ -24,7 +25,7 @@ export default async function getAccountIds(
|
|||||||
return accumulated.sort((a, b) => parseInt(a.id) - parseInt(b.id))
|
return accumulated.sort((a, b) => parseInt(a.id) - parseInt(b.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
return await getAccountIds(address, accumulated)
|
return await getAccountIds(chainConfig, address, accumulated)
|
||||||
} catch {
|
} catch {
|
||||||
return new Promise((_, reject) => reject('No data'))
|
return new Promise((_, reject) => reject('No data'))
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,17 @@ import getAccount from 'api/accounts/getAccount'
|
|||||||
import getWalletAccountIds from 'api/wallets/getAccountIds'
|
import getWalletAccountIds from 'api/wallets/getAccountIds'
|
||||||
import { AccountKind } from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
|
import { AccountKind } from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
|
||||||
|
|
||||||
export default async function getAccounts(kind: AccountKind, address?: string): Promise<Account[]> {
|
export default async function getAccounts(
|
||||||
|
kind: AccountKind,
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
address?: string,
|
||||||
|
): Promise<Account[]> {
|
||||||
if (!address) return new Promise((_, reject) => reject('No address'))
|
if (!address) return new Promise((_, reject) => reject('No address'))
|
||||||
const accountIdsAndKinds = await getWalletAccountIds(address)
|
const accountIdsAndKinds = await getWalletAccountIds(chainConfig, address)
|
||||||
|
|
||||||
const $accounts = accountIdsAndKinds
|
const $accounts = accountIdsAndKinds
|
||||||
.filter((a) => a.kind === kind)
|
.filter((a) => a.kind === kind)
|
||||||
.map((account) => getAccount(account.id))
|
.map((account) => getAccount(chainConfig, account.id))
|
||||||
|
|
||||||
const accounts = await Promise.all($accounts).then((accounts) => accounts)
|
const accounts = await Promise.all($accounts).then((accounts) => accounts)
|
||||||
|
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import { getICNSQueryClient } from 'api/cosmwasm-client'
|
import { getICNSQueryClient } from 'api/cosmwasm-client'
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
import { ChainInfoID } from 'types/enums/wallet'
|
import { ChainInfoID } from 'types/enums/wallet'
|
||||||
|
|
||||||
export default async function getICNS(address?: string): Promise<ICNSResult | undefined> {
|
export default async function getICNS(
|
||||||
if (!address || ENV.CHAIN_ID !== ChainInfoID.Osmosis1) return
|
chainConfig: ChainConfig,
|
||||||
|
address?: string,
|
||||||
|
): Promise<ICNSResult | undefined> {
|
||||||
|
// TODO: Make this also work for different chains?
|
||||||
|
if (!address || chainConfig.id !== ChainInfoID.Osmosis1) return
|
||||||
try {
|
try {
|
||||||
const icnsQueryClient = await getICNSQueryClient()
|
const icnsQueryClient = await getICNSQueryClient(chainConfig)
|
||||||
return icnsQueryClient.primaryName({ address })
|
return icnsQueryClient.primaryName({ address })
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
throw ex
|
throw ex
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { ENV } from 'constants/env'
|
export default async function getWalletBalances(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
export default async function getWalletBalances(address: string): Promise<Coin[]> {
|
address: string,
|
||||||
|
): Promise<Coin[]> {
|
||||||
const uri = '/cosmos/bank/v1beta1/balances/'
|
const uri = '/cosmos/bank/v1beta1/balances/'
|
||||||
|
|
||||||
const response = await fetch(`${ENV.URL_REST}${uri}${address}`)
|
const response = await fetch(`${chainConfig.endpoints.rest}${uri}${address}`)
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
|
@ -13,8 +13,8 @@ import Value, {
|
|||||||
VALUE_META,
|
VALUE_META,
|
||||||
valueSortingFn,
|
valueSortingFn,
|
||||||
} from 'components/Account/AccountBalancesTable/Columns/Value'
|
} from 'components/Account/AccountBalancesTable/Columns/Value'
|
||||||
|
import useMarketAssets from 'hooks/markets/useMarketAssets'
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
import useMarketAssets from 'hooks/useMarketAssets'
|
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
|
||||||
export default function useAccountBalancesColumns(
|
export default function useAccountBalancesColumns(
|
||||||
|
@ -6,6 +6,7 @@ export function getAssetAccountBalanceRow(
|
|||||||
type: 'deposits' | 'borrowing' | 'lending',
|
type: 'deposits' | 'borrowing' | 'lending',
|
||||||
asset: Asset,
|
asset: Asset,
|
||||||
prices: BNCoin[],
|
prices: BNCoin[],
|
||||||
|
assets: Asset[],
|
||||||
position: BNCoin,
|
position: BNCoin,
|
||||||
apy: number,
|
apy: number,
|
||||||
prev?: BNCoin,
|
prev?: BNCoin,
|
||||||
@ -17,7 +18,7 @@ export function getAssetAccountBalanceRow(
|
|||||||
type,
|
type,
|
||||||
symbol: asset.symbol,
|
symbol: asset.symbol,
|
||||||
size: demagnify(amount, asset),
|
size: demagnify(amount, asset),
|
||||||
value: getCoinValue(BNCoin.fromDenomAndBigNumber(denom, amount), prices).toString(),
|
value: getCoinValue(BNCoin.fromDenomAndBigNumber(denom, amount), prices, assets).toString(),
|
||||||
denom,
|
denom,
|
||||||
amount,
|
amount,
|
||||||
apy,
|
apy,
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
getAssetAccountBalanceRow,
|
getAssetAccountBalanceRow,
|
||||||
getVaultAccountBalanceRow,
|
getVaultAccountBalanceRow,
|
||||||
} from 'components/Account/AccountBalancesTable/functions'
|
} from 'components/Account/AccountBalancesTable/functions'
|
||||||
import { ASSETS } from 'constants/assets'
|
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
@ -19,10 +19,9 @@ interface Props {
|
|||||||
|
|
||||||
export default function useAccountBalanceData(props: Props) {
|
export default function useAccountBalanceData(props: Props) {
|
||||||
const { account, updatedAccount, lendingData, borrowingData } = props
|
const { account, updatedAccount, lendingData, borrowingData } = props
|
||||||
|
|
||||||
const { data: hlsStrategies } = useHLSStakingAssets()
|
const { data: hlsStrategies } = useHLSStakingAssets()
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
|
const assets = useAllAssets()
|
||||||
return useMemo<AccountBalanceRow[]>(() => {
|
return useMemo<AccountBalanceRow[]>(() => {
|
||||||
const usedAccount = updatedAccount ?? account
|
const usedAccount = updatedAccount ?? account
|
||||||
const accountDeposits = usedAccount?.deposits ?? []
|
const accountDeposits = usedAccount?.deposits ?? []
|
||||||
@ -32,24 +31,26 @@ export default function useAccountBalanceData(props: Props) {
|
|||||||
|
|
||||||
const deposits: AccountBalanceRow[] = []
|
const deposits: AccountBalanceRow[] = []
|
||||||
accountDeposits.forEach((deposit) => {
|
accountDeposits.forEach((deposit) => {
|
||||||
const asset = ASSETS.find(byDenom(deposit.denom))
|
const asset = assets.find(byDenom(deposit.denom))
|
||||||
if (!asset) return
|
if (!asset) return
|
||||||
const apy = props.isHls
|
const apy = props.isHls
|
||||||
? hlsStrategies.find((strategy) => strategy.denoms.deposit === asset.denom)?.apy ?? 0
|
? hlsStrategies.find((strategy) => strategy.denoms.deposit === asset.denom)?.apy ?? 0
|
||||||
: 0
|
: 0
|
||||||
const prevDeposit = updatedAccount ? account?.deposits.find(byDenom(deposit.denom)) : deposit
|
const prevDeposit = updatedAccount ? account?.deposits.find(byDenom(deposit.denom)) : deposit
|
||||||
deposits.push(getAssetAccountBalanceRow('deposits', asset, prices, deposit, apy, prevDeposit))
|
deposits.push(
|
||||||
|
getAssetAccountBalanceRow('deposits', asset, prices, assets, deposit, apy, prevDeposit),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const lends = accountLends.map((lending) => {
|
const lends = accountLends.map((lending) => {
|
||||||
const asset = ASSETS.find(byDenom(lending.denom)) ?? ASSETS[0]
|
const asset = assets.find(byDenom(lending.denom)) ?? assets[0]
|
||||||
const apy =
|
const apy =
|
||||||
lendingData.find((market) => market.asset.denom === lending.denom)?.apy.deposit ?? 0
|
lendingData.find((market) => market.asset.denom === lending.denom)?.apy.deposit ?? 0
|
||||||
|
|
||||||
const prevLending = updatedAccount
|
const prevLending = updatedAccount
|
||||||
? account?.lends.find((position) => position.denom === lending.denom)
|
? account?.lends.find((position) => position.denom === lending.denom)
|
||||||
: lending
|
: lending
|
||||||
return getAssetAccountBalanceRow('lending', asset, prices, lending, apy, prevLending)
|
return getAssetAccountBalanceRow('lending', asset, prices, assets, lending, apy, prevLending)
|
||||||
})
|
})
|
||||||
|
|
||||||
const vaults = accountVaults.map((vault) => {
|
const vaults = accountVaults.map((vault) => {
|
||||||
@ -61,13 +62,22 @@ export default function useAccountBalanceData(props: Props) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const debts = accountDebts.map((debt) => {
|
const debts = accountDebts.map((debt) => {
|
||||||
const asset = ASSETS.find(byDenom(debt.denom)) ?? ASSETS[0]
|
const asset = assets.find(byDenom(debt.denom)) ?? assets[0]
|
||||||
const apy = borrowingData.find((market) => market.asset.denom === debt.denom)?.apy.borrow ?? 0
|
const apy = borrowingData.find((market) => market.asset.denom === debt.denom)?.apy.borrow ?? 0
|
||||||
const prevDebt = updatedAccount
|
const prevDebt = updatedAccount
|
||||||
? account?.debts.find((position) => position.denom === debt.denom)
|
? account?.debts.find((position) => position.denom === debt.denom)
|
||||||
: debt
|
: debt
|
||||||
return getAssetAccountBalanceRow('borrowing', asset, prices, debt, apy, prevDebt)
|
return getAssetAccountBalanceRow('borrowing', asset, prices, assets, debt, apy, prevDebt)
|
||||||
})
|
})
|
||||||
return [...deposits, ...lends, ...vaults, ...debts]
|
return [...deposits, ...lends, ...vaults, ...debts]
|
||||||
}, [updatedAccount, account, props.isHls, hlsStrategies, prices, lendingData, borrowingData])
|
}, [
|
||||||
|
updatedAccount,
|
||||||
|
account,
|
||||||
|
props.isHls,
|
||||||
|
hlsStrategies,
|
||||||
|
prices,
|
||||||
|
assets,
|
||||||
|
lendingData,
|
||||||
|
borrowingData,
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import { ArrowRight } from 'components/Icons'
|
|||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import { BN_ZERO, MAX_AMOUNT_DECIMALS } from 'constants/math'
|
import { BN_ZERO, MAX_AMOUNT_DECIMALS } from 'constants/math'
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
|
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
@ -40,6 +41,7 @@ export default function AccountComposition(props: Props) {
|
|||||||
const hasChanged = !!updatedAccount
|
const hasChanged = !!updatedAccount
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const { data: hlsStrategies } = useHLSStakingAssets()
|
const { data: hlsStrategies } = useHLSStakingAssets()
|
||||||
|
const assets = useAllAssets()
|
||||||
const { data } = useBorrowMarketAssetsTableData(false)
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
||||||
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
||||||
@ -50,15 +52,15 @@ export default function AccountComposition(props: Props) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const [depositsBalance, lendsBalance, debtsBalance, vaultsBalance] = useMemo(
|
const [depositsBalance, lendsBalance, debtsBalance, vaultsBalance] = useMemo(
|
||||||
() => getAccountPositionValues(account, prices),
|
() => getAccountPositionValues(account, prices, assets),
|
||||||
[account, prices],
|
[account, assets, prices],
|
||||||
)
|
)
|
||||||
const totalBalance = depositsBalance.plus(lendsBalance).plus(vaultsBalance)
|
const totalBalance = depositsBalance.plus(lendsBalance).plus(vaultsBalance)
|
||||||
|
|
||||||
const [updatedPositionValue, updatedDebtsBalance] = useMemo(() => {
|
const [updatedPositionValue, updatedDebtsBalance] = useMemo(() => {
|
||||||
const [updatedDepositsBalance, updatedLendsBalance, updatedDebtsBalance, updatedVaultsBalance] =
|
const [updatedDepositsBalance, updatedLendsBalance, updatedDebtsBalance, updatedVaultsBalance] =
|
||||||
updatedAccount
|
updatedAccount
|
||||||
? getAccountPositionValues(updatedAccount, prices)
|
? getAccountPositionValues(updatedAccount, prices, assets)
|
||||||
: [BN_ZERO, BN_ZERO, BN_ZERO]
|
: [BN_ZERO, BN_ZERO, BN_ZERO]
|
||||||
|
|
||||||
const updatedPositionValue = updatedDepositsBalance
|
const updatedPositionValue = updatedDepositsBalance
|
||||||
@ -66,12 +68,15 @@ export default function AccountComposition(props: Props) {
|
|||||||
.plus(updatedVaultsBalance)
|
.plus(updatedVaultsBalance)
|
||||||
|
|
||||||
return [updatedPositionValue, updatedDebtsBalance]
|
return [updatedPositionValue, updatedDebtsBalance]
|
||||||
}, [updatedAccount, prices])
|
}, [updatedAccount, prices, assets])
|
||||||
|
|
||||||
const netWorth = useMemo(() => calculateAccountBalanceValue(account, prices), [account, prices])
|
const netWorth = useMemo(
|
||||||
|
() => calculateAccountBalanceValue(account, prices, assets),
|
||||||
|
[account, assets, prices],
|
||||||
|
)
|
||||||
const updatedTotalBalance = useMemo(
|
const updatedTotalBalance = useMemo(
|
||||||
() => (updatedAccount ? calculateAccountBalanceValue(updatedAccount, prices) : BN_ZERO),
|
() => (updatedAccount ? calculateAccountBalanceValue(updatedAccount, prices, assets) : BN_ZERO),
|
||||||
[updatedAccount, prices],
|
[updatedAccount, prices, assets],
|
||||||
)
|
)
|
||||||
|
|
||||||
const apr = useMemo(
|
const apr = useMemo(
|
||||||
@ -82,9 +87,10 @@ export default function AccountComposition(props: Props) {
|
|||||||
lendingAssetsData,
|
lendingAssetsData,
|
||||||
prices,
|
prices,
|
||||||
hlsStrategies,
|
hlsStrategies,
|
||||||
|
assets,
|
||||||
props.isHls,
|
props.isHls,
|
||||||
),
|
),
|
||||||
[account, borrowAssetsData, hlsStrategies, lendingAssetsData, prices, props.isHls],
|
[account, assets, borrowAssetsData, hlsStrategies, lendingAssetsData, prices, props.isHls],
|
||||||
)
|
)
|
||||||
const updatedApr = useMemo(
|
const updatedApr = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -95,10 +101,19 @@ export default function AccountComposition(props: Props) {
|
|||||||
lendingAssetsData,
|
lendingAssetsData,
|
||||||
prices,
|
prices,
|
||||||
hlsStrategies,
|
hlsStrategies,
|
||||||
|
assets,
|
||||||
props.isHls,
|
props.isHls,
|
||||||
)
|
)
|
||||||
: BN_ZERO,
|
: BN_ZERO,
|
||||||
[updatedAccount, borrowAssetsData, lendingAssetsData, prices, hlsStrategies, props.isHls],
|
[
|
||||||
|
updatedAccount,
|
||||||
|
borrowAssetsData,
|
||||||
|
lendingAssetsData,
|
||||||
|
prices,
|
||||||
|
hlsStrategies,
|
||||||
|
assets,
|
||||||
|
props.isHls,
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -17,15 +17,16 @@ import Text from 'components/Text'
|
|||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
|
import useAccountIds from 'hooks/accounts/useAccountIds'
|
||||||
|
import useAccounts from 'hooks/accounts/useAccounts'
|
||||||
|
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||||
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useAccountIds from 'hooks/useAccountIds'
|
|
||||||
import useAccounts from 'hooks/useAccounts'
|
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
@ -72,19 +73,23 @@ function AccountDetails(props: Props) {
|
|||||||
updatedAccount || account,
|
updatedAccount || account,
|
||||||
)
|
)
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
|
const assets = useAllAssets()
|
||||||
const accountBalanceValue = useMemo(
|
const accountBalanceValue = useMemo(
|
||||||
() => calculateAccountBalanceValue(updatedAccount ?? account, prices),
|
() => calculateAccountBalanceValue(updatedAccount ?? account, prices, assets),
|
||||||
[updatedAccount, account, prices],
|
[updatedAccount, account, prices, assets],
|
||||||
)
|
)
|
||||||
const coin = BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, accountBalanceValue)
|
const coin = BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, accountBalanceValue)
|
||||||
const leverage = useMemo(() => calculateAccountLeverage(account, prices), [account, prices])
|
const leverage = useMemo(
|
||||||
|
() => calculateAccountLeverage(account, prices, assets),
|
||||||
|
[account, assets, prices],
|
||||||
|
)
|
||||||
const updatedLeverage = useMemo(() => {
|
const updatedLeverage = useMemo(() => {
|
||||||
if (!updatedAccount) return null
|
if (!updatedAccount) return null
|
||||||
const updatedLeverage = calculateAccountLeverage(updatedAccount, prices)
|
const updatedLeverage = calculateAccountLeverage(updatedAccount, prices, assets)
|
||||||
|
|
||||||
if (updatedLeverage.eq(leverage)) return null
|
if (updatedLeverage.eq(leverage)) return null
|
||||||
return updatedLeverage
|
return updatedLeverage
|
||||||
}, [updatedAccount, prices, leverage])
|
}, [updatedAccount, prices, leverage, assets])
|
||||||
|
|
||||||
const { data } = useBorrowMarketAssetsTableData(false)
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
||||||
@ -104,9 +109,10 @@ function AccountDetails(props: Props) {
|
|||||||
lendingAssetsData,
|
lendingAssetsData,
|
||||||
prices,
|
prices,
|
||||||
hlsStrategies,
|
hlsStrategies,
|
||||||
|
assets,
|
||||||
account.kind === 'high_levered_strategy',
|
account.kind === 'high_levered_strategy',
|
||||||
),
|
),
|
||||||
[account, borrowAssetsData, hlsStrategies, lendingAssetsData, prices, updatedAccount],
|
[account, assets, borrowAssetsData, hlsStrategies, lendingAssetsData, prices, updatedAccount],
|
||||||
)
|
)
|
||||||
const isFullWidth = location.pathname.includes('trade') || location.pathname === '/'
|
const isFullWidth = location.pathname.includes('trade') || location.pathname === '/'
|
||||||
|
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
|
|
||||||
|
import AccountFundRow from 'components/Account/AccountFund/AccountFundRow'
|
||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import DepositCapMessage from 'components/DepositCapMessage'
|
import DepositCapMessage from 'components/DepositCapMessage'
|
||||||
import { ArrowRight, Plus } from 'components/Icons'
|
import { ArrowRight, Plus } from 'components/Icons'
|
||||||
import SwitchAutoLend from 'components/Switch/SwitchAutoLend'
|
import SwitchAutoLend from 'components/Switch/SwitchAutoLend'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
|
|
||||||
import WalletBridges from 'components/Wallet/WalletBridges'
|
import WalletBridges from 'components/Wallet/WalletBridges'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||||
import useMarketAssets from 'hooks/useMarketAssets'
|
import useEnableAutoLendGlobal from 'hooks/localStorage/useEnableAutoLendGlobal'
|
||||||
|
import useMarketAssets from 'hooks/markets/useMarketAssets'
|
||||||
import useToggle from 'hooks/useToggle'
|
import useToggle from 'hooks/useToggle'
|
||||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||||
import useWalletBalances from 'hooks/useWalletBalances'
|
import useWalletBalances from 'hooks/useWalletBalances'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { getAssetByDenom, getBaseAsset } from 'utils/assets'
|
|
||||||
import { defaultFee } from 'utils/constants'
|
import { defaultFee } from 'utils/constants'
|
||||||
import { getCapLeftWithBuffer } from 'utils/generic'
|
import { getCapLeftWithBuffer } from 'utils/generic'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
@ -35,16 +33,13 @@ export default function AccountFundContent(props: Props) {
|
|||||||
const deposit = useStore((s) => s.deposit)
|
const deposit = useStore((s) => s.deposit)
|
||||||
const walletAssetModal = useStore((s) => s.walletAssetsModal)
|
const walletAssetModal = useStore((s) => s.walletAssetsModal)
|
||||||
const [isConfirming, setIsConfirming] = useState(false)
|
const [isConfirming, setIsConfirming] = useState(false)
|
||||||
const [lendAssets] = useLocalStorage<boolean>(
|
const [enableAutoLendGlobal] = useEnableAutoLendGlobal()
|
||||||
LocalStorageKeys.LEND_ASSETS,
|
|
||||||
DEFAULT_SETTINGS.lendAssets,
|
|
||||||
)
|
|
||||||
const [fundingAssets, setFundingAssets] = useState<BNCoin[]>([])
|
const [fundingAssets, setFundingAssets] = useState<BNCoin[]>([])
|
||||||
const { data: marketAssets } = useMarketAssets()
|
const { data: marketAssets } = useMarketAssets()
|
||||||
const { data: walletBalances } = useWalletBalances(props.address)
|
const { data: walletBalances } = useWalletBalances(props.address)
|
||||||
const [isLending, toggleIsLending] = useToggle(lendAssets)
|
const [isLending, toggleIsLending] = useToggle(enableAutoLendGlobal)
|
||||||
const { simulateDeposits } = useUpdatedAccount(props.account)
|
const { simulateDeposits } = useUpdatedAccount(props.account)
|
||||||
const baseAsset = getBaseAsset()
|
const baseAsset = useBaseAsset()
|
||||||
|
|
||||||
const hasAssetSelected = fundingAssets.length > 0
|
const hasAssetSelected = fundingAssets.length > 0
|
||||||
const hasFundingAssets =
|
const hasFundingAssets =
|
||||||
@ -150,26 +145,20 @@ export default function AccountFundContent(props: Props) {
|
|||||||
<div>
|
<div>
|
||||||
{!hasAssetSelected && <Text>Please select an asset.</Text>}
|
{!hasAssetSelected && <Text>Please select an asset.</Text>}
|
||||||
{fundingAssets.map((coin) => {
|
{fundingAssets.map((coin) => {
|
||||||
const asset = getAssetByDenom(coin.denom) as Asset
|
|
||||||
|
|
||||||
const balance = balances.find(byDenom(coin.denom))?.amount ?? BN_ZERO
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={asset.symbol}
|
key={coin.denom}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'w-full mb-4',
|
'w-full mb-4',
|
||||||
props.isFullPage && 'w-full p-4 border rounded-base border-white/20 bg-white/5',
|
props.isFullPage && 'w-full p-4 border rounded-base border-white/20 bg-white/5',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<TokenInputWithSlider
|
<AccountFundRow
|
||||||
asset={asset}
|
denom={coin.denom}
|
||||||
onChange={(amount) => updateFundingAssets(amount, asset.denom)}
|
|
||||||
amount={coin.amount ?? BN_ZERO}
|
|
||||||
max={balance}
|
|
||||||
balances={balances}
|
balances={balances}
|
||||||
maxText='Max'
|
amount={coin.amount ?? BN_ZERO}
|
||||||
disabled={isConfirming}
|
isConfirming={isConfirming}
|
||||||
warningMessages={[]}
|
updateFundingAssets={updateFundingAssets}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -4,8 +4,8 @@ import AccountFundContent from 'components/Account/AccountFund/AccountFundConten
|
|||||||
import Card from 'components/Card'
|
import Card from 'components/Card'
|
||||||
import { CircularProgress } from 'components/CircularProgress'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import FullOverlayContent from 'components/FullOverlayContent'
|
import FullOverlayContent from 'components/FullOverlayContent'
|
||||||
|
import useAccounts from 'hooks/accounts/useAccounts'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useAccounts from 'hooks/useAccounts'
|
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
|
||||||
|
34
src/components/Account/AccountFund/AccountFundRow.tsx
Normal file
34
src/components/Account/AccountFund/AccountFundRow.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useAsset from 'hooks/assets/useAsset'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { byDenom } from 'utils/array'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
amount: BigNumber
|
||||||
|
balances: BNCoin[]
|
||||||
|
denom: string
|
||||||
|
isConfirming: boolean
|
||||||
|
updateFundingAssets: (amount: BigNumber, denom: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AccountFundRow(props: Props) {
|
||||||
|
const asset = useAsset(props.denom)
|
||||||
|
|
||||||
|
if (!asset) return null
|
||||||
|
|
||||||
|
const balance = props.balances.find(byDenom(props.denom))?.amount ?? BN_ZERO
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TokenInputWithSlider
|
||||||
|
asset={asset}
|
||||||
|
onChange={(amount) => props.updateFundingAssets(amount, asset.denom)}
|
||||||
|
amount={props.amount}
|
||||||
|
max={balance}
|
||||||
|
balances={props.balances}
|
||||||
|
maxText='Max'
|
||||||
|
disabled={props.isConfirming}
|
||||||
|
warningMessages={[]}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
@ -5,7 +5,8 @@ import Skeleton from 'components/Account/AccountList/Skeleton'
|
|||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import { ArrowDownLine, ArrowUpLine, TrashBin } from 'components/Icons'
|
import { ArrowDownLine, ArrowUpLine, TrashBin } from 'components/Icons'
|
||||||
import SwitchAutoLend from 'components/Switch/SwitchAutoLend'
|
import SwitchAutoLend from 'components/Switch/SwitchAutoLend'
|
||||||
import useAccount from 'hooks/useAccount'
|
import useAccount from 'hooks/accounts/useAccount'
|
||||||
|
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||||
@ -22,13 +23,14 @@ interface Props {
|
|||||||
|
|
||||||
export default function AccountStats(props: Props) {
|
export default function AccountStats(props: Props) {
|
||||||
const { accountId, isActive, setShowMenu } = props
|
const { accountId, isActive, setShowMenu } = props
|
||||||
|
const assets = useAllAssets()
|
||||||
const { data: account } = useAccount(accountId)
|
const { data: account } = useAccount(accountId)
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const { data: hlsStrategies } = useHLSStakingAssets()
|
const { data: hlsStrategies } = useHLSStakingAssets()
|
||||||
|
|
||||||
const positionBalance = useMemo(
|
const positionBalance = useMemo(
|
||||||
() => (!account ? null : calculateAccountBalanceValue(account, prices)),
|
() => (!account ? null : calculateAccountBalanceValue(account, prices, assets)),
|
||||||
[account, prices],
|
[account, assets, prices],
|
||||||
)
|
)
|
||||||
const { health, healthFactor } = useHealthComputer(account)
|
const { health, healthFactor } = useHealthComputer(account)
|
||||||
const { data } = useBorrowMarketAssetsTableData(false)
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
@ -49,9 +51,10 @@ export default function AccountStats(props: Props) {
|
|||||||
lendingAssetsData,
|
lendingAssetsData,
|
||||||
prices,
|
prices,
|
||||||
hlsStrategies,
|
hlsStrategies,
|
||||||
|
assets,
|
||||||
account.kind === 'high_levered_strategy',
|
account.kind === 'high_levered_strategy',
|
||||||
),
|
),
|
||||||
[account, borrowAssetsData, hlsStrategies, lendingAssetsData, prices],
|
[account, assets, borrowAssetsData, hlsStrategies, lendingAssetsData, prices],
|
||||||
)
|
)
|
||||||
|
|
||||||
const deleteAccountHandler = useCallback(() => {
|
const deleteAccountHandler = useCallback(() => {
|
||||||
|
@ -6,8 +6,8 @@ import AccountStats from 'components/Account/AccountList/AccountStats'
|
|||||||
import Card from 'components/Card'
|
import Card from 'components/Card'
|
||||||
import Radio from 'components/Radio'
|
import Radio from 'components/Radio'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
|
import useAccountIds from 'hooks/accounts/useAccountIds'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useAccountIds from 'hooks/useAccountIds'
|
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { getPage, getRoute } from 'utils/route'
|
import { getPage, getRoute } from 'utils/route'
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { Suspense } from 'react'
|
|||||||
|
|
||||||
import AccountMenuContent from 'components/Account/AccountMenuContent'
|
import AccountMenuContent from 'components/Account/AccountMenuContent'
|
||||||
import Loading from 'components/Loading'
|
import Loading from 'components/Loading'
|
||||||
import useAccountIds from 'hooks/useAccountIds'
|
import useAccountIds from 'hooks/accounts/useAccountIds'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
|
||||||
function Content() {
|
function Content() {
|
||||||
|
@ -10,13 +10,12 @@ import { Account, Plus, PlusCircled } from 'components/Icons'
|
|||||||
import Overlay from 'components/Overlay'
|
import Overlay from 'components/Overlay'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import WalletBridges from 'components/Wallet/WalletBridges'
|
import WalletBridges from 'components/Wallet/WalletBridges'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import useAccountIds from 'hooks/accounts/useAccountIds'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||||
|
import useEnableAutoLendGlobal from 'hooks/localStorage/useEnableAutoLendGlobal'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useAccountIds from 'hooks/useAccountIds'
|
|
||||||
import useAutoLend from 'hooks/useAutoLend'
|
import useAutoLend from 'hooks/useAutoLend'
|
||||||
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
|
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
|
||||||
import useToggle from 'hooks/useToggle'
|
import useToggle from 'hooks/useToggle'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { defaultFee } from 'utils/constants'
|
import { defaultFee } from 'utils/constants'
|
||||||
@ -36,14 +35,11 @@ export default function AccountMenuContent() {
|
|||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
|
|
||||||
const createAccount = useStore((s) => s.createAccount)
|
const createAccount = useStore((s) => s.createAccount)
|
||||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
const baseAsset = useBaseAsset()
|
||||||
const [showMenu, setShowMenu] = useToggle()
|
const [showMenu, setShowMenu] = useToggle()
|
||||||
const [isCreating, setIsCreating] = useToggle()
|
const [isCreating, setIsCreating] = useToggle()
|
||||||
const transactionFeeCoinBalance = useCurrentWalletBalance(baseCurrency.denom)
|
const transactionFeeCoinBalance = useCurrentWalletBalance(baseAsset.denom)
|
||||||
const [lendAssets] = useLocalStorage<boolean>(
|
const [enableAutoLendGlobal] = useEnableAutoLendGlobal()
|
||||||
LocalStorageKeys.LEND_ASSETS,
|
|
||||||
DEFAULT_SETTINGS.lendAssets,
|
|
||||||
)
|
|
||||||
const { enableAutoLendAccountId } = useAutoLend()
|
const { enableAutoLendAccountId } = useAutoLend()
|
||||||
|
|
||||||
const hasCreditAccounts = !!accountIds?.length
|
const hasCreditAccounts = !!accountIds?.length
|
||||||
@ -65,7 +61,7 @@ export default function AccountMenuContent() {
|
|||||||
|
|
||||||
if (accountId) {
|
if (accountId) {
|
||||||
navigate(getRoute(getPage(pathname), searchParams, address, accountId))
|
navigate(getRoute(getPage(pathname), searchParams, address, accountId))
|
||||||
if (lendAssets) enableAutoLendAccountId(accountId)
|
if (enableAutoLendGlobal) enableAutoLendAccountId(accountId)
|
||||||
useStore.setState({
|
useStore.setState({
|
||||||
focusComponent: {
|
focusComponent: {
|
||||||
component: <AccountFund />,
|
component: <AccountFund />,
|
||||||
@ -83,7 +79,7 @@ export default function AccountMenuContent() {
|
|||||||
pathname,
|
pathname,
|
||||||
searchParams,
|
searchParams,
|
||||||
address,
|
address,
|
||||||
lendAssets,
|
enableAutoLendGlobal,
|
||||||
enableAutoLendAccountId,
|
enableAutoLendAccountId,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -14,10 +14,11 @@ import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
|||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
|
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||||
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
@ -34,13 +35,14 @@ export default function AccountSummary(props: Props) {
|
|||||||
DEFAULT_SETTINGS.accountSummaryTabs,
|
DEFAULT_SETTINGS.accountSummaryTabs,
|
||||||
)
|
)
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
|
const assets = useAllAssets()
|
||||||
const updatedAccount = useStore((s) => s.updatedAccount)
|
const updatedAccount = useStore((s) => s.updatedAccount)
|
||||||
const accountBalance = useMemo(
|
const accountBalance = useMemo(
|
||||||
() =>
|
() =>
|
||||||
props.account
|
props.account
|
||||||
? calculateAccountBalanceValue(updatedAccount ?? props.account, prices)
|
? calculateAccountBalanceValue(updatedAccount ?? props.account, prices, assets)
|
||||||
: BN_ZERO,
|
: BN_ZERO,
|
||||||
[props.account, updatedAccount, prices],
|
[props.account, updatedAccount, prices, assets],
|
||||||
)
|
)
|
||||||
const { data } = useBorrowMarketAssetsTableData(false)
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
||||||
@ -55,16 +57,16 @@ export default function AccountSummary(props: Props) {
|
|||||||
const { health: updatedHealth, healthFactor: updatedHealthFactor } =
|
const { health: updatedHealth, healthFactor: updatedHealthFactor } =
|
||||||
useHealthComputer(updatedAccount)
|
useHealthComputer(updatedAccount)
|
||||||
const leverage = useMemo(
|
const leverage = useMemo(
|
||||||
() => (props.account ? calculateAccountLeverage(props.account, prices) : BN_ZERO),
|
() => (props.account ? calculateAccountLeverage(props.account, prices, assets) : BN_ZERO),
|
||||||
[props.account, prices],
|
[props.account, prices, assets],
|
||||||
)
|
)
|
||||||
const updatedLeverage = useMemo(() => {
|
const updatedLeverage = useMemo(() => {
|
||||||
if (!updatedAccount) return null
|
if (!updatedAccount) return null
|
||||||
const updatedLeverage = calculateAccountLeverage(updatedAccount, prices)
|
const updatedLeverage = calculateAccountLeverage(updatedAccount, prices, assets)
|
||||||
|
|
||||||
if (updatedLeverage.eq(leverage)) return null
|
if (updatedLeverage.eq(leverage)) return null
|
||||||
return updatedLeverage
|
return updatedLeverage
|
||||||
}, [updatedAccount, prices, leverage])
|
}, [updatedAccount, prices, assets, leverage])
|
||||||
|
|
||||||
const handleToggle = useCallback(
|
const handleToggle = useCallback(
|
||||||
(index: number) => {
|
(index: number) => {
|
||||||
|
@ -5,8 +5,8 @@ import HealthIcon from 'components/Account/Health/HealthIcon'
|
|||||||
import HealthTooltip from 'components/Account/Health/HealthTooltip'
|
import HealthTooltip from 'components/Account/Health/HealthTooltip'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
import useHealthColor from 'hooks/useHealthColor'
|
import useHealthColor from 'hooks/useHealthColor'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
|
||||||
import { getHealthIndicatorColors } from 'utils/healthIndicator'
|
import { getHealthIndicatorColors } from 'utils/healthIndicator'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -5,8 +5,8 @@ import HealthIcon from 'components/Account/Health/HealthIcon'
|
|||||||
import HealthTooltip from 'components/Account/Health/HealthTooltip'
|
import HealthTooltip from 'components/Account/Health/HealthTooltip'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
import useHealthColorAndLabel from 'hooks/useHealthColor'
|
import useHealthColorAndLabel from 'hooks/useHealthColor'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
|
||||||
import { computeHealthGaugePercentage } from 'utils/accounts'
|
import { computeHealthGaugePercentage } from 'utils/accounts'
|
||||||
import { getHealthIndicatorColors } from 'utils/healthIndicator'
|
import { getHealthIndicatorColors } from 'utils/healthIndicator'
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { ReactElement, useMemo } from 'react'
|
import { ReactElement, useMemo } from 'react'
|
||||||
|
|
||||||
import { CircularProgress } from 'components/CircularProgress'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
|
@ -14,7 +14,7 @@ import Text from 'components/Text'
|
|||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
import { formatValue } from 'utils/formatters'
|
import { formatValue } from 'utils/formatters'
|
||||||
|
|
||||||
export const RiskChart = ({ data }: RiskChartProps) => {
|
export const RiskChart = ({ data }: RiskChartProps) => {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useLocation } from 'react-router-dom'
|
|
||||||
import { useEffect, useMemo } from 'react'
|
import { useEffect, useMemo } from 'react'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { getPage } from 'utils/route'
|
import { getPage } from 'utils/route'
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ import { useCallback } from 'react'
|
|||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import ActionButton from 'components/Button/ActionButton'
|
import ActionButton from 'components/Button/ActionButton'
|
||||||
import { HandCoins, Plus } from 'components/Icons'
|
import { HandCoins, Plus } from 'components/Icons'
|
||||||
|
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { getEnabledMarketAssets } from 'utils/assets'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: BorrowMarketTableData
|
data: BorrowMarketTableData
|
||||||
@ -12,7 +12,7 @@ interface Props {
|
|||||||
|
|
||||||
export default function BorrowActionButtons(props: Props) {
|
export default function BorrowActionButtons(props: Props) {
|
||||||
const { asset, debt } = props.data
|
const { asset, debt } = props.data
|
||||||
const marketAssets = getEnabledMarketAssets()
|
const marketAssets = useMarketEnabledAssets()
|
||||||
const currentAsset = marketAssets.find((a) => a.denom === asset.denom)
|
const currentAsset = marketAssets.find((a) => a.denom === asset.denom)
|
||||||
|
|
||||||
const borrowHandler = useCallback(() => {
|
const borrowHandler = useCallback(() => {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import AvailableBorrowingsTable from 'components/Borrow/Table/AvailableBorrowingsTable'
|
import AvailableBorrowingsTable from 'components/Borrow/Table/AvailableBorrowingsTable'
|
||||||
import DepositedBorrowingsTable from 'components/Borrow/Table/DepositedBorrowingsTable'
|
import DepositedBorrowingsTable from 'components/Borrow/Table/DepositedBorrowingsTable'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useBorrowEnabledAssets from 'hooks/assets/useBorrowEnabledAssets'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
import { getBorrowEnabledAssets } from 'utils/assets'
|
|
||||||
|
|
||||||
export default function Borrowings() {
|
export default function Borrowings() {
|
||||||
const { data } = useBorrowMarketAssetsTableData()
|
const { data } = useBorrowMarketAssetsTableData()
|
||||||
@ -19,7 +19,7 @@ export default function Borrowings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Fallback() {
|
function Fallback() {
|
||||||
const assets = getBorrowEnabledAssets()
|
const assets = useBorrowEnabledAssets()
|
||||||
const data: BorrowMarketTableData[] = assets.map((asset) => ({
|
const data: BorrowMarketTableData[] = assets.map((asset) => ({
|
||||||
asset,
|
asset,
|
||||||
apy: {
|
apy: {
|
||||||
|
@ -2,8 +2,8 @@ import { Row } from '@tanstack/react-table'
|
|||||||
|
|
||||||
import AmountAndValue from 'components/AmountAndValue'
|
import AmountAndValue from 'components/AmountAndValue'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { getEnabledMarketAssets } from 'utils/assets'
|
|
||||||
|
|
||||||
export const DEBT_META = {
|
export const DEBT_META = {
|
||||||
accessorKey: 'debt',
|
accessorKey: 'debt',
|
||||||
@ -33,7 +33,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Debt(props: Props) {
|
export default function Debt(props: Props) {
|
||||||
const marketAssets = getEnabledMarketAssets()
|
const marketAssets = useMarketEnabledAssets()
|
||||||
const asset = marketAssets.find(byDenom(props.data.asset.denom))
|
const asset = marketAssets.find(byDenom(props.data.asset.denom))
|
||||||
|
|
||||||
if (!asset) return null
|
if (!asset) return null
|
||||||
|
@ -3,8 +3,7 @@ import { Row } from '@tanstack/react-table'
|
|||||||
import AmountAndValue from 'components/AmountAndValue'
|
import AmountAndValue from 'components/AmountAndValue'
|
||||||
import Loading from 'components/Loading'
|
import Loading from 'components/Loading'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import { byDenom } from 'utils/array'
|
import useAsset from 'hooks/assets/useAsset'
|
||||||
import { getEnabledMarketAssets } from 'utils/assets'
|
|
||||||
import { demagnify } from 'utils/formatters'
|
import { demagnify } from 'utils/formatters'
|
||||||
|
|
||||||
export const LIQUIDITY_META = {
|
export const LIQUIDITY_META = {
|
||||||
@ -32,8 +31,7 @@ interface Props {
|
|||||||
|
|
||||||
export default function Liquidity(props: Props) {
|
export default function Liquidity(props: Props) {
|
||||||
const { liquidity, asset: borrowAsset } = props.data
|
const { liquidity, asset: borrowAsset } = props.data
|
||||||
const marketAssets = getEnabledMarketAssets()
|
const asset = useAsset(borrowAsset.denom)
|
||||||
const asset = marketAssets.find(byDenom(borrowAsset.denom))
|
|
||||||
|
|
||||||
if (!asset) return null
|
if (!asset) return null
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import Text from 'components/Text'
|
|||||||
import { Tooltip } from 'components/Tooltip'
|
import { Tooltip } from 'components/Tooltip'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
balance: number
|
balance: number
|
||||||
|
@ -5,8 +5,8 @@ import { ACCOUNT_MENU_BUTTON_ID } from 'components/Account/AccountMenuContent'
|
|||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import { Account, PlusCircled } from 'components/Icons'
|
import { Account, PlusCircled } from 'components/Icons'
|
||||||
import WalletConnectButton from 'components/Wallet/WalletConnectButton'
|
import WalletConnectButton from 'components/Wallet/WalletConnectButton'
|
||||||
|
import useAccountIds from 'hooks/accounts/useAccountIds'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useAccountIds from 'hooks/useAccountIds'
|
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
|
||||||
export default function ActionButton(props: ButtonProps) {
|
export default function ActionButton(props: ButtonProps) {
|
||||||
|
@ -18,7 +18,7 @@ import { CircularProgress } from 'components/CircularProgress'
|
|||||||
import { ChevronDown } from 'components/Icons'
|
import { ChevronDown } from 'components/Icons'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
|
|
||||||
const Button = React.forwardRef(function Button(
|
const Button = React.forwardRef(function Button(
|
||||||
{
|
{
|
||||||
@ -33,6 +33,7 @@ const Button = React.forwardRef(function Button(
|
|||||||
text,
|
text,
|
||||||
variant = 'solid',
|
variant = 'solid',
|
||||||
onClick,
|
onClick,
|
||||||
|
onMouseOver,
|
||||||
leftIcon,
|
leftIcon,
|
||||||
rightIcon,
|
rightIcon,
|
||||||
iconClassName,
|
iconClassName,
|
||||||
@ -97,6 +98,7 @@ const Button = React.forwardRef(function Button(
|
|||||||
id={id}
|
id={id}
|
||||||
ref={ref as LegacyRef<HTMLButtonElement>}
|
ref={ref as LegacyRef<HTMLButtonElement>}
|
||||||
onClick={isDisabled ? () => {} : onClick}
|
onClick={isDisabled ? () => {} : onClick}
|
||||||
|
onMouseOver={isDisabled ? () => {} : onMouseOver}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
autoFocus={autoFocus}
|
autoFocus={autoFocus}
|
||||||
>
|
>
|
||||||
|
19
src/components/Chain/ChainLogo.tsx
Normal file
19
src/components/Chain/ChainLogo.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Neutron, Osmo } from 'components/Icons'
|
||||||
|
import { ChainInfoID } from 'types/enums/wallet'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
chainID: ChainInfoID
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ChainLogo(props: Props) {
|
||||||
|
const { chainID, className } = props
|
||||||
|
|
||||||
|
switch (chainID) {
|
||||||
|
case ChainInfoID.Pion1:
|
||||||
|
return <Neutron className={className} />
|
||||||
|
|
||||||
|
default:
|
||||||
|
return <Osmo className={className} />
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ import classNames from 'classnames'
|
|||||||
import { CheckCircled } from 'components/Icons'
|
import { CheckCircled } from 'components/Icons'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
color?: string
|
color?: string
|
||||||
|
@ -2,7 +2,7 @@ import classNames from 'classnames'
|
|||||||
|
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
color?: string
|
color?: string
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||||
import { VAULT_DEPOSIT_BUFFER } from 'constants/vaults'
|
import { VAULT_DEPOSIT_BUFFER } from 'constants/vaults'
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
import useAsset from 'hooks/assets/useAsset'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
depositCap: DepositCap
|
depositCap: DepositCap
|
||||||
@ -13,7 +13,7 @@ export default function DepositCapCell(props: Props) {
|
|||||||
.multipliedBy(100)
|
.multipliedBy(100)
|
||||||
.integerValue()
|
.integerValue()
|
||||||
const depositCapUsed = Math.min(percent.toNumber(), 100)
|
const depositCapUsed = Math.min(percent.toNumber(), 100)
|
||||||
const decimals = getAssetByDenom(props.depositCap.denom)?.decimals ?? 6
|
const decimals = useAsset(props.depositCap.denom)?.decimals ?? 6
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TitleAndSubCell
|
<TitleAndSubCell
|
||||||
|
@ -4,8 +4,8 @@ import { HTMLAttributes } from 'react'
|
|||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import { InfoCircle } from 'components/Icons'
|
import { InfoCircle } from 'components/Icons'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
|
import useAsset from 'hooks/assets/useAsset'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
|
||||||
|
|
||||||
interface Props extends HTMLAttributes<HTMLDivElement> {
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||||
action: 'buy' | 'deposit' | 'fund'
|
action: 'buy' | 'deposit' | 'fund'
|
||||||
@ -24,27 +24,32 @@ export default function DepositCapMessage(props: Props) {
|
|||||||
<Text size='xs' className='text-white/40'>{`Unfortunately you're not able to ${
|
<Text size='xs' className='text-white/40'>{`Unfortunately you're not able to ${
|
||||||
props.action
|
props.action
|
||||||
} more than the following amount${props.coins.length > 1 ? 's' : ''}:`}</Text>
|
} more than the following amount${props.coins.length > 1 ? 's' : ''}:`}</Text>
|
||||||
{props.coins.map((coin) => {
|
{props.coins.map((coin) => (
|
||||||
const asset = getAssetByDenom(coin.denom)
|
<AmountMessage key={coin.denom} coin={coin} />
|
||||||
|
))}
|
||||||
if (!asset) return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={coin.denom} className='flex gap-1'>
|
|
||||||
<Text size='xs'>Cap Left:</Text>
|
|
||||||
<FormattedNumber
|
|
||||||
amount={Math.max(coin.amount.toNumber(), 0)}
|
|
||||||
options={{
|
|
||||||
decimals: asset.decimals,
|
|
||||||
maxDecimals: asset.decimals,
|
|
||||||
suffix: ` ${asset.symbol}`,
|
|
||||||
}}
|
|
||||||
className='text-xs text-white/60'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AmountMessageProps {
|
||||||
|
coin: BNCoin
|
||||||
|
}
|
||||||
|
function AmountMessage(props: AmountMessageProps) {
|
||||||
|
const asset = useAsset(props.coin.denom)
|
||||||
|
if (!asset) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={props.coin.denom} className='flex gap-1'>
|
||||||
|
<Text size='xs'>Cap Left:</Text>
|
||||||
|
<FormattedNumber
|
||||||
|
amount={Math.max(0, props.coin.amount.toNumber())}
|
||||||
|
options={{
|
||||||
|
decimals: asset.decimals,
|
||||||
|
suffix: ` ${asset.symbol}`,
|
||||||
|
}}
|
||||||
|
className='text-xs text-white/60'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -2,13 +2,12 @@ import classNames from 'classnames'
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||||
|
import useDisplayCurrencyAssets from 'hooks/assets/useDisplayCurrencyAssets'
|
||||||
|
import useDisplayCurrency from 'hooks/localStorage/useDisplayCurrency'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { getDisplayCurrencies } from 'utils/assets'
|
|
||||||
import { getCoinValue } from 'utils/formatters'
|
import { getCoinValue } from 'utils/formatters'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
@ -22,11 +21,9 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function DisplayCurrency(props: Props) {
|
export default function DisplayCurrency(props: Props) {
|
||||||
const displayCurrencies = getDisplayCurrencies()
|
const displayCurrencies = useDisplayCurrencyAssets()
|
||||||
const [displayCurrency] = useLocalStorage<string>(
|
const assets = useAllAssets()
|
||||||
LocalStorageKeys.DISPLAY_CURRENCY,
|
const [displayCurrency] = useDisplayCurrency()
|
||||||
DEFAULT_SETTINGS.displayCurrency,
|
|
||||||
)
|
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
|
|
||||||
const displayCurrencyAsset = useMemo(
|
const displayCurrencyAsset = useMemo(
|
||||||
@ -38,7 +35,7 @@ export default function DisplayCurrency(props: Props) {
|
|||||||
const isUSD = displayCurrencyAsset.id === 'USD'
|
const isUSD = displayCurrencyAsset.id === 'USD'
|
||||||
|
|
||||||
const amount = useMemo(() => {
|
const amount = useMemo(() => {
|
||||||
const coinValue = getCoinValue(props.coin, prices)
|
const coinValue = getCoinValue(props.coin, prices, assets)
|
||||||
|
|
||||||
if (displayCurrency === ORACLE_DENOM) return coinValue.toNumber()
|
if (displayCurrency === ORACLE_DENOM) return coinValue.toNumber()
|
||||||
|
|
||||||
@ -46,10 +43,11 @@ export default function DisplayCurrency(props: Props) {
|
|||||||
const displayPrice = getCoinValue(
|
const displayPrice = getCoinValue(
|
||||||
BNCoin.fromDenomAndBigNumber(displayCurrency, BN(1).shiftedBy(displayDecimals)),
|
BNCoin.fromDenomAndBigNumber(displayCurrency, BN(1).shiftedBy(displayDecimals)),
|
||||||
prices,
|
prices,
|
||||||
|
assets,
|
||||||
)
|
)
|
||||||
|
|
||||||
return coinValue.div(displayPrice).toNumber()
|
return coinValue.div(displayPrice).toNumber()
|
||||||
}, [displayCurrency, displayCurrencyAsset.decimals, prices, props.coin])
|
}, [assets, displayCurrency, displayCurrencyAsset.decimals, prices, props.coin])
|
||||||
|
|
||||||
const isLessThanACent = (isUSD && amount < 0.01 && amount > 0) || (amount === 0 && props.showZero)
|
const isLessThanACent = (isUSD && amount < 0.01 && amount > 0) || (amount === 0 && props.showZero)
|
||||||
const smallerThanPrefix = isLessThanACent ? '< ' : ''
|
const smallerThanPrefix = isLessThanACent ? '< ' : ''
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import AssetImage from 'components/Asset/AssetImage'
|
import AssetImage from 'components/Asset/AssetImage'
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
import useAsset from 'hooks/assets/useAsset'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
primaryDenom: string
|
primaryDenom: string
|
||||||
@ -7,8 +7,8 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function DoubleLogo(props: Props) {
|
export default function DoubleLogo(props: Props) {
|
||||||
const primaryAsset = getAssetByDenom(props.primaryDenom)
|
const primaryAsset = useAsset(props.primaryDenom)
|
||||||
const secondaryAsset = getAssetByDenom(props.secondaryDenom)
|
const secondaryAsset = useAsset(props.secondaryDenom)
|
||||||
|
|
||||||
if (!primaryAsset || !secondaryAsset) return null
|
if (!primaryAsset || !secondaryAsset) return null
|
||||||
|
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
import { Suspense } from 'react'
|
|
||||||
|
|
||||||
import Card from 'components/Card'
|
|
||||||
import VaultCard from 'components/Earn/Farm/VaultCard'
|
|
||||||
import useVaults from 'hooks/useVaults'
|
|
||||||
|
|
||||||
function Content() {
|
|
||||||
const { data: vaults } = useVaults()
|
|
||||||
if (!vaults) return null
|
|
||||||
const featuredVaults = vaults.filter((vault) => vault.isFeatured)
|
|
||||||
|
|
||||||
if (!featuredVaults.length) return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
title='Featured vaults'
|
|
||||||
className='w-full mb-4 h-fit bg-white/5'
|
|
||||||
contentClassName='grid grid-cols-3'
|
|
||||||
>
|
|
||||||
{featuredVaults.map((vault) => (
|
|
||||||
<VaultCard
|
|
||||||
key={vault.address}
|
|
||||||
vault={vault}
|
|
||||||
title={vault.name}
|
|
||||||
subtitle='Hot off the presses'
|
|
||||||
provider={vault.provider}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function FeaturedVaults() {
|
|
||||||
return (
|
|
||||||
<Suspense fallback={null}>
|
|
||||||
<Content />
|
|
||||||
</Suspense>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
import ActionButton from 'components/Button/ActionButton'
|
|
||||||
import DoubleLogo from 'components/DoubleLogo'
|
|
||||||
import Text from 'components/Text'
|
|
||||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
|
||||||
import useStore from 'store'
|
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
|
||||||
import { formatPercent, formatValue } from 'utils/formatters'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
vault: Vault
|
|
||||||
title: string
|
|
||||||
subtitle: string
|
|
||||||
provider?: string
|
|
||||||
unbondingPeriod?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function VaultCard(props: Props) {
|
|
||||||
const currentAccount = useCurrentAccount()
|
|
||||||
|
|
||||||
function openVaultModal() {
|
|
||||||
useStore.setState({
|
|
||||||
vaultModal: {
|
|
||||||
vault: props.vault,
|
|
||||||
selectedBorrowDenoms: [props.vault.denoms.secondary],
|
|
||||||
isCreate: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='border-r-[1px] border-r-white/10 p-4'>
|
|
||||||
<div className='flex justify-between mb-8 align-center'>
|
|
||||||
<div>
|
|
||||||
<Text size='xs' className='mb-2 text-white/60'>
|
|
||||||
{props.subtitle}
|
|
||||||
</Text>
|
|
||||||
<span className='flex'>
|
|
||||||
<Text className='mr-2 font-bold'>{props.title}</Text>
|
|
||||||
{props.provider && (
|
|
||||||
<Text size='sm' className='text-white/60'>
|
|
||||||
via {props.provider}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<DoubleLogo
|
|
||||||
primaryDenom={props.vault.denoms.primary}
|
|
||||||
secondaryDenom={props.vault.denoms.secondary}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='flex justify-between mb-6'>
|
|
||||||
<TitleAndSubCell
|
|
||||||
className='text-xs'
|
|
||||||
title={props.vault.apy ? formatPercent(props.vault.apy, 2) : '-'}
|
|
||||||
sub={'APY'}
|
|
||||||
/>
|
|
||||||
<TitleAndSubCell
|
|
||||||
className='text-xs'
|
|
||||||
title={`${props.vault.lockup.duration} ${props.vault.lockup.timeframe}`}
|
|
||||||
sub={'Lockup'}
|
|
||||||
/>
|
|
||||||
<TitleAndSubCell
|
|
||||||
className='text-xs'
|
|
||||||
title={formatValue(props.vault.cap.used.integerValue().toNumber() || '0', {
|
|
||||||
abbreviated: true,
|
|
||||||
decimals: getAssetByDenom(props.vault.cap.denom)?.decimals,
|
|
||||||
})}
|
|
||||||
sub={'TVL'}
|
|
||||||
/>
|
|
||||||
<TitleAndSubCell
|
|
||||||
className='text-xs'
|
|
||||||
title={formatValue(props.vault.cap.max.integerValue().toNumber() || '0', {
|
|
||||||
abbreviated: true,
|
|
||||||
decimals: getAssetByDenom(props.vault.cap.denom)?.decimals,
|
|
||||||
})}
|
|
||||||
sub={'Deposit Cap'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<ActionButton onClick={openVaultModal} color='secondary' text='Deposit' className='w-full' />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -7,8 +7,8 @@ import { AccountArrowDown, LockLocked, LockUnlocked, Plus } from 'components/Ico
|
|||||||
import { Tooltip } from 'components/Tooltip'
|
import { Tooltip } from 'components/Tooltip'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { VaultStatus } from 'types/enums/vault'
|
import { VaultStatus } from 'types/enums/vault'
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ import { ChevronRight } from 'components/Icons'
|
|||||||
import NotificationBanner from 'components/NotificationBanner'
|
import NotificationBanner from 'components/NotificationBanner'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -3,13 +3,11 @@ import { Suspense, useMemo } from 'react'
|
|||||||
import AvailableVaultsTable from 'components/Earn/Farm/Table/AvailableVaultsTable'
|
import AvailableVaultsTable from 'components/Earn/Farm/Table/AvailableVaultsTable'
|
||||||
import DepositedVaultsTable from 'components/Earn/Farm/Table/DepositedVaultsTable'
|
import DepositedVaultsTable from 'components/Earn/Farm/Table/DepositedVaultsTable'
|
||||||
import VaultUnlockBanner from 'components/Earn/Farm/VaultUnlockBanner'
|
import VaultUnlockBanner from 'components/Earn/Farm/VaultUnlockBanner'
|
||||||
import { ENV } from 'constants/env'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults'
|
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useDepositedVaults from 'hooks/useDepositedVaults'
|
import useDepositedVaults from 'hooks/useDepositedVaults'
|
||||||
import useVaults from 'hooks/useVaults'
|
import useVaults from 'hooks/useVaults'
|
||||||
import { NETWORK } from 'types/enums/network'
|
import useStore from 'store'
|
||||||
import { VaultStatus } from 'types/enums/vault'
|
import { VaultStatus } from 'types/enums/vault'
|
||||||
|
|
||||||
function Content() {
|
function Content() {
|
||||||
@ -17,11 +15,10 @@ function Content() {
|
|||||||
const { data: vaults } = useVaults()
|
const { data: vaults } = useVaults()
|
||||||
const { data: depositedVaults } = useDepositedVaults(accountId || '')
|
const { data: depositedVaults } = useDepositedVaults(accountId || '')
|
||||||
|
|
||||||
const vaultsMetaData =
|
const vaultMetaData = useStore((s) => s.chainConfig.vaults)
|
||||||
ENV.NETWORK === NETWORK.TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
|
|
||||||
|
|
||||||
const { deposited, available } = useMemo(() => {
|
const { deposited, available } = useMemo(() => {
|
||||||
return vaultsMetaData.reduce(
|
return vaultMetaData.reduce(
|
||||||
(prev: { deposited: DepositedVault[]; available: Vault[] }, curr) => {
|
(prev: { deposited: DepositedVault[]; available: Vault[] }, curr) => {
|
||||||
if (!vaults) return prev
|
if (!vaults) return prev
|
||||||
const vault = vaults.find((vault) => vault.address === curr.address)
|
const vault = vaults.find((vault) => vault.address === curr.address)
|
||||||
@ -37,7 +34,7 @@ function Content() {
|
|||||||
},
|
},
|
||||||
{ deposited: [], available: [] },
|
{ deposited: [], available: [] },
|
||||||
)
|
)
|
||||||
}, [vaults, depositedVaults, vaultsMetaData])
|
}, [vaults, depositedVaults, vaultMetaData])
|
||||||
|
|
||||||
const unlockedVaults: DepositedVault[] = []
|
const unlockedVaults: DepositedVault[] = []
|
||||||
|
|
||||||
@ -63,7 +60,7 @@ function Content() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Fallback() {
|
function Fallback() {
|
||||||
const vaults = ENV.NETWORK === NETWORK.TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
|
const vaults = useStore((s) => s.chainConfig.vaults)
|
||||||
const mockVaults: Vault[] = vaults.map((vault) => ({
|
const mockVaults: Vault[] = vaults.map((vault) => ({
|
||||||
...vault,
|
...vault,
|
||||||
apy: null,
|
apy: null,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import AvailableLendsTable from 'components/Earn/Lend/Table/AvailableLendsTable'
|
import AvailableLendsTable from 'components/Earn/Lend/Table/AvailableLendsTable'
|
||||||
import DepositedLendsTable from 'components/Earn/Lend/Table/DepositedLendsTable'
|
import DepositedLendsTable from 'components/Earn/Lend/Table/DepositedLendsTable'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useLendEnabledAssets from 'hooks/assets/useLendEnabledAssets'
|
||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
import { getLendEnabledAssets } from 'utils/assets'
|
|
||||||
|
|
||||||
export default function Lends() {
|
export default function Lends() {
|
||||||
const { accountLentAssets, availableAssets, allAssets } = useLendingMarketAssetsTableData()
|
const { accountLentAssets, availableAssets, allAssets } = useLendingMarketAssetsTableData()
|
||||||
@ -19,7 +19,8 @@ export default function Lends() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Fallback() {
|
function Fallback() {
|
||||||
const assets = getLendEnabledAssets()
|
const assets = useLendEnabledAssets()
|
||||||
|
|
||||||
const data: LendingMarketTableData[] = assets.map((asset) => ({
|
const data: LendingMarketTableData[] = assets.map((asset) => ({
|
||||||
asset,
|
asset,
|
||||||
marketDepositCap: BN_ZERO,
|
marketDepositCap: BN_ZERO,
|
||||||
|
@ -4,7 +4,7 @@ import { animated, useSpring } from 'react-spring'
|
|||||||
|
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
import { formatValue } from 'utils/formatters'
|
import { formatValue } from 'utils/formatters'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -4,7 +4,7 @@ import { ReactElement, ReactNode } from 'react'
|
|||||||
import { Tooltip } from 'components/Tooltip'
|
import { Tooltip } from 'components/Tooltip'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
tooltip: string | ReactNode
|
tooltip: string | ReactNode
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user