feat: replace graphql requests with cosmwasm queries (#225)
* feat: replace graphql requests with cosmwasm queries * feat: concurent price and market fetching
This commit is contained in:
parent
de89ecb7ed
commit
0c959d5097
@ -20,7 +20,6 @@
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"bignumber.js": "^9.1.1",
|
||||
"classnames": "^2.3.2",
|
||||
"graphql-request": "^6.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"next": "^13.4.3",
|
||||
"react": "^18.2.0",
|
||||
|
@ -7,7 +7,7 @@ let _cosmWasmClient: CosmWasmClient
|
||||
const getClient = async () => {
|
||||
try {
|
||||
if (!_cosmWasmClient) {
|
||||
_cosmWasmClient = await CosmWasmClient.connect(ENV.URL_RPC || '')
|
||||
_cosmWasmClient = await CosmWasmClient.connect(ENV.URL_RPC)
|
||||
}
|
||||
|
||||
return _cosmWasmClient
|
||||
|
@ -1,29 +0,0 @@
|
||||
import { gql, request as gqlRequest } from 'graphql-request'
|
||||
|
||||
import { ENV } from 'constants/env'
|
||||
|
||||
export default async function getBalances() {
|
||||
const result = await gqlRequest<Result>(
|
||||
ENV.URL_GQL,
|
||||
gql`
|
||||
query RedbankBalances {
|
||||
bank {
|
||||
balance(
|
||||
address: "${ENV.ADDRESS_RED_BANK}"
|
||||
) {
|
||||
amount
|
||||
denom
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
)
|
||||
|
||||
return result.bank.balance
|
||||
}
|
||||
|
||||
interface Result {
|
||||
bank: {
|
||||
balance: Coin[]
|
||||
}
|
||||
}
|
@ -1,54 +1,24 @@
|
||||
import { gql, request as gqlRequest } from 'graphql-request'
|
||||
|
||||
import { ENV } from 'constants/env'
|
||||
import { denomToKey, getContractQuery, keyToDenom } from 'utils/query'
|
||||
import getMarkets from 'api/markets/getMarkets'
|
||||
import { getClient } from 'api/cosmwasm-client'
|
||||
|
||||
export default async function getMarketDebts(): Promise<Coin[]> {
|
||||
const markets: Market[] = await getMarkets()
|
||||
try {
|
||||
const markets: Market[] = await getMarkets()
|
||||
const client = await getClient()
|
||||
|
||||
let query = ''
|
||||
|
||||
markets.forEach((asset) => {
|
||||
query += getContractQuery(
|
||||
denomToKey(asset.denom),
|
||||
ENV.ADDRESS_RED_BANK || '',
|
||||
`
|
||||
{
|
||||
const debtQueries = markets.map((asset) =>
|
||||
client.queryContractSmart(ENV.ADDRESS_RED_BANK, {
|
||||
underlying_debt_amount: {
|
||||
denom: "${asset.denom}"
|
||||
amount_scaled: "${asset.debtTotalScaled}"
|
||||
}
|
||||
}`,
|
||||
denom: asset.denom,
|
||||
amount_scaled: asset.debtTotalScaled,
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
const debtsResults = await Promise.all(debtQueries)
|
||||
|
||||
const result = await gqlRequest<DebtsQuery>(
|
||||
ENV.URL_GQL,
|
||||
gql`
|
||||
query RedbankBalances {
|
||||
debts: wasm {
|
||||
${query}
|
||||
}
|
||||
}
|
||||
`,
|
||||
)
|
||||
|
||||
if (result) {
|
||||
const debts = Object.keys(result.debts).map((key) => {
|
||||
return {
|
||||
denom: keyToDenom(key),
|
||||
amount: result.debts[key],
|
||||
}
|
||||
})
|
||||
return debts
|
||||
}
|
||||
|
||||
return new Promise((_, reject) => reject('No data'))
|
||||
}
|
||||
|
||||
interface DebtsQuery {
|
||||
debts: {
|
||||
[key: string]: string
|
||||
return debtsResults.map<Coin>((debt, index) => ({ denom: markets[index].denom, amount: debt }))
|
||||
} catch (ex) {
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +1,27 @@
|
||||
import { gql, request as gqlRequest } from 'graphql-request'
|
||||
|
||||
import { ENV } from 'constants/env'
|
||||
import { denomToKey, getContractQuery, keyToDenom } from 'utils/query'
|
||||
import getMarkets from 'api/markets/getMarkets'
|
||||
import { getClient } from 'api/cosmwasm-client'
|
||||
|
||||
export default async function getMarketDeposits(): Promise<Coin[]> {
|
||||
const markets = await getMarkets()
|
||||
try {
|
||||
const markets: Market[] = await getMarkets()
|
||||
const client = await getClient()
|
||||
|
||||
let query = ''
|
||||
|
||||
markets.forEach((market: Market) => {
|
||||
query += getContractQuery(
|
||||
denomToKey(market.denom),
|
||||
ENV.ADDRESS_RED_BANK || '',
|
||||
`
|
||||
{
|
||||
underlying_liquidity_amount: {
|
||||
denom: "${market.denom}"
|
||||
amount_scaled: "${market.collateralTotalScaled}"
|
||||
}
|
||||
}`,
|
||||
const depositQueries = markets.map((asset) =>
|
||||
client.queryContractSmart(ENV.ADDRESS_RED_BANK, {
|
||||
underlying_liquidity_amount: {
|
||||
denom: asset.denom,
|
||||
amount_scaled: asset.collateralTotalScaled,
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
const depositsResults = await Promise.all(depositQueries)
|
||||
|
||||
const result = await gqlRequest<DepositsQuery>(
|
||||
ENV.URL_GQL,
|
||||
gql`
|
||||
query RedbankBalances {
|
||||
deposits: wasm {
|
||||
${query}
|
||||
}
|
||||
}
|
||||
`,
|
||||
)
|
||||
|
||||
if (result) {
|
||||
const deposits = Object.keys(result.deposits).map((key) => {
|
||||
return {
|
||||
denom: keyToDenom(key),
|
||||
amount: result.deposits[key],
|
||||
}
|
||||
})
|
||||
return deposits
|
||||
}
|
||||
|
||||
return new Promise((_, reject) => reject('No data'))
|
||||
}
|
||||
|
||||
interface DepositsQuery {
|
||||
deposits: {
|
||||
[key: string]: string
|
||||
return depositsResults.map<Coin>((deposit, index) => ({
|
||||
denom: markets[index].denom,
|
||||
amount: deposit,
|
||||
}))
|
||||
} catch (ex) {
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
@ -1,41 +1,24 @@
|
||||
import { gql, request as gqlRequest } from 'graphql-request'
|
||||
|
||||
import { ENV } from 'constants/env'
|
||||
import { getMarketAssets } from 'utils/assets'
|
||||
import { denomToKey } from 'utils/query'
|
||||
import { getEnabledMarketAssets } from 'utils/assets'
|
||||
import { resolveMarketResponses } from 'utils/resolvers'
|
||||
import { getClient } from 'api/cosmwasm-client'
|
||||
|
||||
export default async function getMarkets(): Promise<Market[]> {
|
||||
const marketAssets = getMarketAssets()
|
||||
try {
|
||||
const enabledAssets = getEnabledMarketAssets()
|
||||
const client = await getClient()
|
||||
|
||||
const marketQueries = marketAssets.map(
|
||||
(asset: Asset) =>
|
||||
`${denomToKey(asset.denom)}: contractQuery(
|
||||
contractAddress: "${ENV.ADDRESS_RED_BANK}"
|
||||
query: { market: { denom: "${asset.denom}" } }
|
||||
)`,
|
||||
)
|
||||
const marketQueries = enabledAssets.map((asset) =>
|
||||
client.queryContractSmart(ENV.ADDRESS_RED_BANK, {
|
||||
market: {
|
||||
denom: asset.denom,
|
||||
},
|
||||
}),
|
||||
)
|
||||
const marketResults = await Promise.all(marketQueries)
|
||||
|
||||
const result = await gqlRequest<RedBankData>(
|
||||
ENV.URL_GQL,
|
||||
gql`
|
||||
query RedbankQuery {
|
||||
rbwasmkey: wasm {
|
||||
${marketQueries}
|
||||
}
|
||||
}
|
||||
`,
|
||||
)
|
||||
|
||||
const markets = marketAssets.map((asset) => {
|
||||
const market = result.rbwasmkey[`${denomToKey(asset.denom)}`]
|
||||
return market
|
||||
})
|
||||
return resolveMarketResponses(markets)
|
||||
}
|
||||
|
||||
interface RedBankData {
|
||||
rbwasmkey: {
|
||||
[key: string]: MarketResponse
|
||||
return resolveMarketResponses(marketResults)
|
||||
} catch (ex) {
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
@ -1,59 +1,36 @@
|
||||
import { gql, request as gqlRequest } from 'graphql-request'
|
||||
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import { ENV } from 'constants/env'
|
||||
import { getMarketAssets } from 'utils/assets'
|
||||
import { getEnabledMarketAssets } from 'utils/assets'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { getClient } from 'api/cosmwasm-client'
|
||||
|
||||
export default async function getPrices(): Promise<Coin[]> {
|
||||
const marketAssets = getMarketAssets()
|
||||
const baseCurrency = ASSETS[0]
|
||||
try {
|
||||
const enabledAssets = getEnabledMarketAssets()
|
||||
const client = await getClient()
|
||||
const baseCurrency = ASSETS[0]
|
||||
|
||||
const result = await gqlRequest<TokenPricesResult>(
|
||||
ENV.URL_GQL,
|
||||
gql`
|
||||
query PriceOracle {
|
||||
prices: wasm {
|
||||
${marketAssets.map((asset) => {
|
||||
return `${asset.id}: contractQuery(
|
||||
contractAddress: "${ENV.ADDRESS_ORACLE}"
|
||||
query: {
|
||||
price: {
|
||||
denom: "${asset.denom}"
|
||||
}
|
||||
}
|
||||
)`
|
||||
})}
|
||||
}
|
||||
const priceQueries = enabledAssets.map((asset) =>
|
||||
client.queryContractSmart(ENV.ADDRESS_ORACLE, {
|
||||
price: {
|
||||
denom: asset.denom,
|
||||
},
|
||||
}),
|
||||
)
|
||||
const priceResults: PriceResult[] = await Promise.all(priceQueries)
|
||||
|
||||
const assetPrices = priceResults.map(({ denom, price }, index) => {
|
||||
const asset = enabledAssets[index]
|
||||
const decimalDiff = asset.decimals - baseCurrency.decimals
|
||||
|
||||
return {
|
||||
denom,
|
||||
amount: BN(price).shiftedBy(decimalDiff).toString(),
|
||||
}
|
||||
`,
|
||||
)
|
||||
})
|
||||
|
||||
const data: Coin[] = Object.values(result?.prices).reduce((acc: Coin[], curr) => {
|
||||
const asset = marketAssets.find((asset) => asset.denom === curr.denom)
|
||||
const additionalDecimals = asset
|
||||
? asset.decimals > baseCurrency.decimals
|
||||
? asset.decimals - baseCurrency.decimals
|
||||
: 0
|
||||
: 0
|
||||
|
||||
return [
|
||||
...acc,
|
||||
{
|
||||
denom: curr.denom,
|
||||
amount: BN(curr.price).shiftedBy(additionalDecimals).toString(),
|
||||
},
|
||||
] as Coin[]
|
||||
}, [])
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
interface TokenPricesResult {
|
||||
prices: {
|
||||
[key: string]: {
|
||||
denom: string
|
||||
price: string
|
||||
}
|
||||
return assetPrices
|
||||
} catch (ex) {
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { Row } from '@tanstack/react-table'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import useStore from 'store'
|
||||
import { getMarketAssets } from 'utils/assets'
|
||||
import { getEnabledMarketAssets } from 'utils/assets'
|
||||
|
||||
type AssetRowProps = {
|
||||
row: Row<BorrowAsset | BorrowAssetActive>
|
||||
@ -12,7 +12,7 @@ type AssetRowProps = {
|
||||
}
|
||||
|
||||
export default function AssetExpanded(props: AssetRowProps) {
|
||||
const marketAssets = getMarketAssets()
|
||||
const marketAssets = getEnabledMarketAssets()
|
||||
const asset = marketAssets.find((asset) => asset.denom === props.row.original.denom)
|
||||
let isActive: boolean = false
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { flexRender, Row } from '@tanstack/react-table'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { getMarketAssets } from 'utils/assets'
|
||||
import { getEnabledMarketAssets } from 'utils/assets'
|
||||
|
||||
type AssetRowProps = {
|
||||
row: Row<BorrowAsset | BorrowAssetActive>
|
||||
@ -9,7 +9,7 @@ type AssetRowProps = {
|
||||
}
|
||||
|
||||
export const AssetRow = (props: AssetRowProps) => {
|
||||
const marketAssets = getMarketAssets()
|
||||
const marketAssets = getEnabledMarketAssets()
|
||||
const asset = marketAssets.find((asset) => asset.denom === props.row.original.denom)
|
||||
|
||||
if (!asset) return null
|
||||
|
@ -17,7 +17,7 @@ import { ChevronDown, SortAsc, SortDesc, SortNone } from 'components/Icons'
|
||||
import Loading from 'components/Loading'
|
||||
import Text from 'components/Text'
|
||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||
import { getMarketAssets } from 'utils/assets'
|
||||
import { getEnabledMarketAssets } from 'utils/assets'
|
||||
import { formatPercent } from 'utils/formatters'
|
||||
|
||||
type Props = {
|
||||
@ -26,7 +26,7 @@ type Props = {
|
||||
|
||||
export const BorrowTable = (props: Props) => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([])
|
||||
const marketAssets = getMarketAssets()
|
||||
const marketAssets = getEnabledMarketAssets()
|
||||
|
||||
const columns = React.useMemo<ColumnDef<BorrowAsset | BorrowAssetActive>[]>(
|
||||
() => [
|
||||
|
@ -2,7 +2,7 @@ import { Suspense } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
|
||||
import Card from 'components/Card'
|
||||
import { getMarketAssets } from 'utils/assets'
|
||||
import { getEnabledMarketAssets } from 'utils/assets'
|
||||
import { BorrowTable } from 'components/Borrow/BorrowTable'
|
||||
import useAccountDebts from 'hooks/useAccountDebts'
|
||||
import useMarketBorrowings from 'hooks/useMarketBorrowings'
|
||||
@ -16,7 +16,7 @@ function Content(props: Props) {
|
||||
const { data: debtData } = useAccountDebts(accountId)
|
||||
const { data: borrowData } = useMarketBorrowings()
|
||||
|
||||
const marketAssets = getMarketAssets()
|
||||
const marketAssets = getEnabledMarketAssets()
|
||||
|
||||
function getBorrowAssets() {
|
||||
return marketAssets.reduce(
|
||||
@ -60,7 +60,7 @@ function Content(props: Props) {
|
||||
}
|
||||
|
||||
function Fallback() {
|
||||
const marketAssets = getMarketAssets()
|
||||
const marketAssets = getEnabledMarketAssets()
|
||||
|
||||
const available: BorrowAsset[] = marketAssets.reduce((prev: BorrowAsset[], curr) => {
|
||||
prev.push({ ...curr, borrowRate: null, liquidity: null })
|
||||
|
@ -18,7 +18,7 @@ import Text from 'components/Text'
|
||||
import { IS_TESTNET } from 'constants/env'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useStore from 'store'
|
||||
import { getBaseAsset, getMarketAssets } from 'utils/assets'
|
||||
import { getBaseAsset, getEnabledMarketAssets } from 'utils/assets'
|
||||
import { formatValue, truncate } from 'utils/formatters'
|
||||
import useWalletBalances from 'hooks/useWalletBalances'
|
||||
|
||||
@ -26,7 +26,7 @@ export default function ConnectedButton() {
|
||||
// ---------------
|
||||
// EXTERNAL HOOKS
|
||||
// ---------------
|
||||
const marketAssets = getMarketAssets()
|
||||
const marketAssets = getEnabledMarketAssets()
|
||||
const { disconnect } = useWallet()
|
||||
const { disconnect: terminate } = useWalletManager()
|
||||
const address = useStore((s) => s.address)
|
||||
|
5
src/types/interfaces/responses.d.ts
vendored
5
src/types/interfaces/responses.d.ts
vendored
@ -29,3 +29,8 @@ interface MarketResponse {
|
||||
borrow_enabled: boolean
|
||||
deposit_cap: string
|
||||
}
|
||||
|
||||
interface PriceResult {
|
||||
denom: string
|
||||
price: string
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ export function getAssetBySymbol(symbol: string) {
|
||||
return ASSETS.find((asset) => asset.symbol === symbol)
|
||||
}
|
||||
|
||||
export function getMarketAssets(): Asset[] {
|
||||
export function getEnabledMarketAssets(): Asset[] {
|
||||
return ASSETS.filter((asset) => asset.isEnabled && asset.isMarket)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
import { getMarketAssets } from 'utils/assets'
|
||||
import { getEnabledMarketAssets } from 'utils/assets'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export function truncate(text = '', [h, t]: [number, number] = [6, 6]): string {
|
||||
@ -126,7 +126,7 @@ export function formatPercent(percent: number | string, minDecimals?: number) {
|
||||
}
|
||||
|
||||
export function formatAmountWithSymbol(coin: Coin) {
|
||||
const marketAssets = getMarketAssets()
|
||||
const marketAssets = getEnabledMarketAssets()
|
||||
|
||||
const asset = marketAssets.find((asset) => asset.denom === coin.denom)
|
||||
|
||||
@ -157,7 +157,7 @@ export function demagnify(amount: number | string | BigNumber, asset: Asset) {
|
||||
|
||||
export function convertToDisplayAmount(coin: Coin, displayCurrency: Asset, prices: Coin[]) {
|
||||
const price = prices.find((price) => price.denom === coin.denom)
|
||||
const asset = getMarketAssets().find((asset) => asset.denom === coin.denom)
|
||||
const asset = getEnabledMarketAssets().find((asset) => asset.denom === coin.denom)
|
||||
const displayPrice = prices.find((price) => price.denom === displayCurrency.denom)
|
||||
|
||||
if (!price || !asset || !displayPrice) return '0'
|
||||
|
24
yarn.lock
24
yarn.lock
@ -2059,7 +2059,7 @@
|
||||
"@ethersproject/properties" "^5.7.0"
|
||||
"@ethersproject/strings" "^5.7.0"
|
||||
|
||||
"@graphql-typed-document-node/core@^3.1.1", "@graphql-typed-document-node/core@^3.2.0":
|
||||
"@graphql-typed-document-node/core@^3.1.1":
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
|
||||
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
|
||||
@ -4719,13 +4719,6 @@ create-hmac@^1.1.4, create-hmac@^1.1.7:
|
||||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
cross-fetch@^3.1.5:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz"
|
||||
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
|
||||
dependencies:
|
||||
node-fetch "2.6.7"
|
||||
|
||||
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
|
||||
@ -6072,14 +6065,6 @@ graphemer@^1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
|
||||
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
|
||||
|
||||
graphql-request@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.0.0.tgz#9c8b6a0c341f289e049936d03cc9205300faae1c"
|
||||
integrity sha512-2BmHTuglonjZvmNVw6ZzCfFlW/qkIPds0f+Qdi/Lvjsl3whJg2uvHmSvHnLWhUTEw6zcxPYAHiZoPvSVKOZ7Jw==
|
||||
dependencies:
|
||||
"@graphql-typed-document-node/core" "^3.2.0"
|
||||
cross-fetch "^3.1.5"
|
||||
|
||||
graphql-tag@^2.12.6:
|
||||
version "2.12.6"
|
||||
resolved "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz"
|
||||
@ -7532,13 +7517,6 @@ node-addon-api@^5.0.0:
|
||||
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz"
|
||||
integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==
|
||||
|
||||
node-fetch@2.6.7:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz"
|
||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^2.6.7:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz"
|
||||
|
Loading…
Reference in New Issue
Block a user