Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Money Market user data on wallet page #2041

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/api/borrow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { UiPoolDataProvider } from "@aave/contract-helpers"
import { formatReserves, formatUserSummary } from "@aave/math-utils"
import { useQuery } from "@tanstack/react-query"
import { isTestnetRpcUrl } from "api/provider"
import { useRpcProvider } from "providers/rpcProvider"
import { useMemo } from "react"
import {
AaveV3HydrationMainnet,
AaveV3HydrationTestnet,
} from "sections/lending/ui-config/addresses"
import { useAccount } from "sections/web3-connect/Web3Connect.utils"
import { H160, isEvmAccount } from "utils/evm"
import { QUERY_KEYS } from "utils/queryKeys"

export const useUserBorrowSummary = (givenAddress?: string) => {
const { account } = useAccount()
const { api, evm, isLoaded } = useRpcProvider()

const address = givenAddress || account?.address

const isEvm = isEvmAccount(address)

const evmAddress = useMemo(() => {
if (!address) return ""
if (isEvm) return H160.fromAccount(address)
return H160.fromSS58(address)
}, [isEvm, address])

return useQuery(
QUERY_KEYS.borrowUserSummary(evmAddress),
async () => {
const isTestnet = isTestnetRpcUrl(evm.connection.url)

const contracts = isTestnet
? AaveV3HydrationTestnet
: AaveV3HydrationMainnet

const poolDataContract = new UiPoolDataProvider({
uiPoolDataProviderAddress: contracts.UI_POOL_DATA_PROVIDER,
provider: evm,
chainId: parseFloat(import.meta.env.VITE_EVM_CHAIN_ID),
})

const [reserves, user, timestamp] = await Promise.all([
poolDataContract.getReservesHumanized({
lendingPoolAddressProvider: contracts.POOL_ADDRESSES_PROVIDER,
}),
poolDataContract.getUserReservesHumanized({
lendingPoolAddressProvider: contracts.POOL_ADDRESSES_PROVIDER,
user: evmAddress,
}),
api.query.timestamp.now(),
])

const { baseCurrencyData, reservesData } = reserves
const { userEmodeCategoryId, userReserves } = user

const currentTimestamp = timestamp.toNumber() / 1000

const formattedReserves = formatReserves({
currentTimestamp,
reserves: reservesData,
marketReferencePriceInUsd:
baseCurrencyData.marketReferenceCurrencyPriceInUsd,
marketReferenceCurrencyDecimals:
baseCurrencyData.marketReferenceCurrencyDecimals,
})

return formatUserSummary({
currentTimestamp,
marketReferencePriceInUsd:
baseCurrencyData.marketReferenceCurrencyPriceInUsd,
marketReferenceCurrencyDecimals:
baseCurrencyData.marketReferenceCurrencyDecimals,
userReserves,
formattedReserves,
userEmodeCategoryId,
})
},
{
retry: false,
enabled: isLoaded && !!evmAddress,
},
)
}
23 changes: 16 additions & 7 deletions src/api/external/bifrost.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useQuery } from "@tanstack/react-query"
import { useQuery, UseQueryOptions } from "@tanstack/react-query"
import { QUERY_KEYS } from "utils/queryKeys"

type BifrostAPY = {
Expand All @@ -7,10 +7,19 @@ type BifrostAPY = {
apyReward: string
}

export const useBifrostVDotApy = () => {
return useQuery(QUERY_KEYS.bifrostVDotApy, async () => {
const res = await fetch("https://dapi.bifrost.io/api/site")
const data = await res.json()
return data["vDOT"] as BifrostAPY
})
export const useBifrostVDotApy = (
options: UseQueryOptions<BifrostAPY> = {},
) => {
return useQuery<BifrostAPY>(
QUERY_KEYS.bifrostVDotApy,
async () => {
const res = await fetch("https://dapi.bifrost.io/api/site")
const data = await res.json()
return data["vDOT"] as BifrostAPY
},
{
refetchOnWindowFocus: false,
...options,
},
)
}
4 changes: 4 additions & 0 deletions src/api/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { identity, undefinedNoop } from "utils/helpers"
import { ExternalAssetCursor } from "@galacticcouncil/apps"
import { getExternalId } from "utils/externalAssets"
import { pingRpc } from "utils/rpc"
import { PolkadotEvmRpcProvider } from "utils/provider"

export type TEnv = "testnet" | "mainnet"
export type ProviderProps = {
Expand Down Expand Up @@ -273,8 +274,11 @@ export const useProviderData = () => {

const balanceClient = new BalanceClient(api)

const evm = new PolkadotEvmRpcProvider(api)

return {
api,
evm,
tradeRouter,
poolService,
balanceClient,
Expand Down
5 changes: 5 additions & 0 deletions src/providers/rpcProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ import { useDisplayAssetStore } from "utils/displayAsset"
import { useShareTokens } from "api/xyk"
import { AssetsProvider } from "./assets"
import { differenceInHours } from "date-fns"
import { PolkadotEvmRpcProvider } from "utils/provider"

type TProviderContext = {
api: ApiPromise
evm: PolkadotEvmRpcProvider
tradeRouter: TradeRouter
poolService: PoolService
balanceClient: BalanceClient
Expand All @@ -30,6 +32,7 @@ type TProviderContext = {
const ProviderContext = createContext<TProviderContext>({
isLoaded: false,
api: {} as TProviderContext["api"],
evm: {} as TProviderContext["evm"],
tradeRouter: {} as TradeRouter,
featureFlags: {} as TProviderContext["featureFlags"],
poolService: {} as TProviderContext["poolService"],
Expand Down Expand Up @@ -103,6 +106,7 @@ export const RpcProvider = ({ children }: { children: ReactNode }) => {
return {
poolService: providerData.poolService,
api: providerData.api,
evm: providerData.evm,
tradeRouter: providerData.tradeRouter,
balanceClient: providerData.balanceClient,
featureFlags: providerData.featureFlags,
Expand All @@ -113,6 +117,7 @@ export const RpcProvider = ({ children }: { children: ReactNode }) => {
return {
isLoaded: false,
api: {} as TProviderContext["api"],
evm: {} as TProviderContext["evm"],
tradeRouter: {} as TradeRouter,
balanceClient: {} as BalanceClient,
featureFlags: {
Expand Down
4 changes: 3 additions & 1 deletion src/sections/lending/ui/header/DashboardHeaderValues.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ export const DashboardHeaderValues: FC<{
(BN(underlyingBalance).gt(0) || BN(totalBorrows).gt(0)),
)

const { data: vDotApy, isLoading: isVDotApyLoading } = useBifrostVDotApy()
const { data: vDotApy, isLoading: isVDotApyLoading } = useBifrostVDotApy({
enabled: vDotSuppliedOrBorrowed,
})

return (
<>
Expand Down
11 changes: 10 additions & 1 deletion src/sections/wallet/assets/WalletAssets.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useDisplayShareTokenPrice } from "utils/displayAsset"
import { useAssetsData } from "./table/data/WalletAssetsTableData.utils"
import { useAccountAssets } from "api/deposits"
import BigNumber from "bignumber.js"
import { useUserBorrowSummary } from "api/borrow"

type AssetCategory = "all" | "assets" | "liquidity" | "farming"

Expand Down Expand Up @@ -46,6 +47,7 @@ export const useWalletAssetsTotals = ({
}: {
address?: string
} = {}) => {
const borrows = useUserBorrowSummary(address)
const assets = useAssetsData({ isAllAssets: false, address })
const lpPositions = useOmnipoolPositionsData({ address })
const farmsTotal = useFarmDepositsTotal(address)
Expand All @@ -61,6 +63,8 @@ export const useWalletAssetsTotals = ({
shareTokenBalances.map((token) => token.asset.id),
)

console.log(borrows.error)

const assetsTotal = useMemo(
() =>
assets.data.reduce((acc, cur) => {
Expand Down Expand Up @@ -103,17 +107,21 @@ export const useWalletAssetsTotals = ({
}, "0")
}, [shareTokenBalances, spotPrices.data])

const borrowsTotal = borrows.data?.totalBorrowsUSD ?? "0"

const balanceTotal = useMemo(
() =>
BigNumber(assetsTotal)
.plus(farmsTotal.value)
.plus(lpTotal)
.plus(xykTotal)
.plus(borrowsTotal)
.toString(),
[assetsTotal, farmsTotal.value, lpTotal, xykTotal],
[assetsTotal, farmsTotal.value, lpTotal, xykTotal, borrowsTotal],
)

const isLoading =
borrows.isLoading ||
assets.isLoading ||
lpPositions.isLoading ||
farmsTotal.isLoading ||
Expand All @@ -125,6 +133,7 @@ export const useWalletAssetsTotals = ({
farmsTotal: farmsTotal.value,
lpTotal: BigNumber(lpTotal).plus(xykTotal).toString(),
balanceTotal,
borrowsTotal: borrows.data?.totalBorrowsUSD ?? "0",
isLoading,
}
}
32 changes: 25 additions & 7 deletions src/sections/wallet/assets/header/WalletAssetsHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@ type Props = { disconnected?: boolean }

export const WalletAssetsHeader = ({ disconnected }: Props) => {
const { t } = useTranslation()
const { isLoading, balanceTotal, assetsTotal, farmsTotal, lpTotal } =
useWalletAssetsTotals()
const {
isLoading,
balanceTotal,
assetsTotal,
farmsTotal,
borrowsTotal,
lpTotal,
} = useWalletAssetsTotals()

return (
<HeaderValues
skeletonHeight={[19, 38]}
skeletonHeight={[19, 28]}
sx={{ align: ["normal", "end"] }}
values={[
{
Expand All @@ -21,7 +28,7 @@ export const WalletAssetsHeader = ({ disconnected }: Props) => {
content: (
<WalletAssetsHeaderDisplay
isLoading={isLoading}
fontSize={[19, 30]}
fontSize={[19, 24]}
value={balanceTotal}
/>
),
Expand All @@ -32,7 +39,7 @@ export const WalletAssetsHeader = ({ disconnected }: Props) => {
content: (
<WalletAssetsHeaderDisplay
isLoading={isLoading}
fontSize={[19, 30]}
fontSize={[19, 24]}
value={assetsTotal}
/>
),
Expand All @@ -43,7 +50,7 @@ export const WalletAssetsHeader = ({ disconnected }: Props) => {
content: (
<WalletAssetsHeaderDisplay
isLoading={isLoading}
fontSize={[19, 30]}
fontSize={[19, 24]}
value={lpTotal}
/>
),
Expand All @@ -54,11 +61,22 @@ export const WalletAssetsHeader = ({ disconnected }: Props) => {
content: (
<WalletAssetsHeaderDisplay
isLoading={isLoading}
fontSize={[19, 30]}
fontSize={[19, 24]}
value={farmsTotal}
/>
),
},
{
label: "Borrows",
disconnected: disconnected,
content: (
<WalletAssetsHeaderDisplay
isLoading={isLoading}
fontSize={[19, 24]}
value={borrowsTotal}
/>
),
},
]}
/>
)
Expand Down
28 changes: 28 additions & 0 deletions src/utils/provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { getNetwork, JsonRpcProvider, Network } from "@ethersproject/providers"
import { ApiPromise, WsProvider } from "@polkadot/api"

export class PolkadotEvmRpcProvider extends JsonRpcProvider {
provider: WsProvider

constructor(api: ApiPromise) {
const provider = PolkadotEvmRpcProvider.getProviderInstance(api)
const path = provider.endpoint
super(path)
this.provider = provider
}

async _uncachedDetectNetwork(): Promise<Network> {
const chainId = await this.send("eth_chainId", [])
return getNetwork(parseInt(chainId, 16))
}

static getProviderInstance(api: ApiPromise) {
// @ts-expect-error Property '_options' is protected
const options = api?._options
return options?.provider as WsProvider
}

send(method: string, params: Array<any> = []): Promise<any> {
return this.provider.send(method, params)
}
}
1 change: 1 addition & 0 deletions src/utils/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,4 +331,5 @@ export const QUERY_KEYS = {
) => ["xcmTransfer", asset, srcAddr, srcChain, dstAddr, dstChain],
externalApi: (chain: string) => ["externalApi", chain],
bifrostVDotApy: ["bifrostVDotApy"],
borrowUserSummary: (address: string) => ["borrowUserSummary", address],
} as const
Loading