Account balances endpoint (#147)

* add accounts/positions to api

* strong type apis
This commit is contained in:
Bob van der Helm 2023-04-03 13:30:16 +02:00 committed by GitHub
parent 7efb7908c0
commit 8e0bb97839
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 117 additions and 37 deletions

View File

@ -9,10 +9,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const accountId = req.query.id
const account = await (await fetch(`${ENV.URL_API}/accounts/${accountId}${VERCEL_BYPASS}`)).json()
const position: Position = await (
await fetch(`${ENV.URL_API}/accounts/${accountId}${VERCEL_BYPASS}`)
).json()
if (account) {
return res.status(200).json(account.debts)
if (position) {
return res.status(200).json(position.debts)
}
return res.status(404)

View File

@ -9,10 +9,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const accountId = req.query.id
const account = await (await fetch(`${ENV.URL_API}/accounts/${accountId}${VERCEL_BYPASS}`)).json()
const position: Position = await (
await fetch(`${ENV.URL_API}/accounts/${accountId}${VERCEL_BYPASS}`)
).json()
if (account) {
return res.status(200).json(account.deposits)
if (position) {
return res.status(200).json(position.deposits)
}
return res.status(404)

View File

@ -2,6 +2,7 @@ import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import { NextApiRequest, NextApiResponse } from 'next'
import { ENV, ENV_MISSING_MESSAGE } from 'constants/env'
import { resolvePositionResponse } from 'utils/resolvers'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!ENV.URL_RPC || !ENV.ADDRESS_CREDIT_MANAGER) {
@ -12,14 +13,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const client = await CosmWasmClient.connect(ENV.URL_RPC)
const data = await client.queryContractSmart(ENV.ADDRESS_CREDIT_MANAGER, {
const data: PositionResponse = await client.queryContractSmart(ENV.ADDRESS_CREDIT_MANAGER, {
positions: {
account_id: accountId,
},
})
if (data) {
return res.status(200).json(data)
return res.status(200).json(resolvePositionResponse(data))
}
return res.status(404)

View File

@ -10,7 +10,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return res.status(404).json(ENV_MISSING_MESSAGE)
}
const marketAssets = getMarketAssets()
const $liquidity = fetch(`${ENV.URL_API}/markets/liquidity${VERCEL_BYPASS}`)
const $markets = fetch(`${ENV.URL_API}/markets${VERCEL_BYPASS}`)
const $prices = fetch(`${ENV.URL_API}/prices${VERCEL_BYPASS}`)
@ -18,16 +17,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const borrow: BorrowAsset[] = await Promise.all([$liquidity, $markets, $prices]).then(
async ([$liquidity, $markets, $prices]) => {
const liquidity: Coin[] = await $liquidity.json()
const markets: Market[] = await $markets.json()
const borrowEnabledMarkets: Market[] = (await $markets.json()).filter(
(market: Market) => market.borrowEnabled,
)
const prices: Coin[] = await $prices.json()
return marketAssets.map((asset) => {
const currentMarket = markets.find((market) => market.denom === asset.denom)
const price = prices.find((coin) => coin.denom === asset.denom)?.amount ?? '1'
const amount = liquidity.find((coin) => coin.denom === asset.denom)?.amount ?? '0'
return borrowEnabledMarkets.map((market) => {
const price = prices.find((coin) => coin.denom === market.denom)?.amount ?? '1'
const amount = liquidity.find((coin) => coin.denom === market.denom)?.amount ?? '0'
return {
denom: asset.denom,
borrowRate: currentMarket?.borrow_rate ?? '0',
denom: market.denom,
borrowRate: market.borrowRate ?? 0,
liquidity: {
amount: amount,
value: new BigNumber(amount).times(price).toString(),

View File

@ -21,7 +21,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
{
underlying_debt_amount: {
denom: "${asset.denom}"
amount_scaled: "${asset.debt_total_scaled}"
amount_scaled: "${asset.debtTotalScaled}"
}
}`,
)

View File

@ -13,15 +13,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
let query = ''
markets.forEach((asset: any) => {
markets.forEach((market: Market) => {
query += getContractQuery(
denomToKey(asset.denom),
denomToKey(market.denom),
ENV.ADDRESS_RED_BANK || '',
`
{
underlying_liquidity_amount: {
denom: "${asset.denom}"
amount_scaled: "${asset.collateral_total_scaled}"
denom: "${market.denom}"
amount_scaled: "${market.collateralTotalScaled}"
}
}`,
)

View File

@ -4,6 +4,7 @@ import { NextApiRequest, NextApiResponse } from 'next'
import { ENV, ENV_MISSING_MESSAGE } from 'constants/env'
import { getMarketAssets } from 'utils/assets'
import { denomToKey } from 'utils/query'
import { resolveMarketResponses } from 'utils/resolvers'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!ENV.URL_GQL || !ENV.ADDRESS_RED_BANK || !ENV.ADDRESS_INCENTIVES) {
@ -35,11 +36,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const market = result.rbwasmkey[`${denomToKey(asset.denom)}`]
return market
})
return res.status(200).json(markets)
return res.status(200).json(resolveMarketResponses(markets))
}
interface RedBankData {
rbwasmkey: {
[key: string]: Market
[key: string]: MarketResponse
}
}

View File

@ -0,0 +1,35 @@
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import { NextApiRequest, NextApiResponse } from 'next'
import { ENV, ENV_MISSING_MESSAGE, VERCEL_BYPASS } from 'constants/env'
import { resolvePositionResponses } from 'utils/resolvers'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!ENV.URL_RPC || !ENV.ADDRESS_CREDIT_MANAGER || !ENV.URL_API) {
return res.status(404).json(ENV_MISSING_MESSAGE)
}
const address = req.query.address
const accounts: string[] = await (
await fetch(`${ENV.URL_API}/wallets/${address}/accounts${VERCEL_BYPASS}`)
).json()
const client = await CosmWasmClient.connect(ENV.URL_RPC)
const $positions: Promise<PositionResponse>[] = accounts.map((account) =>
client.queryContractSmart(ENV.ADDRESS_CREDIT_MANAGER!, {
positions: {
account_id: `${account}`,
},
}),
)
const positions = await Promise.all($positions).then((positions) => positions)
if (positions) {
return res.status(200).json(resolvePositionResponses(positions))
}
return res.status(404)
}

6
src/types/interfaces/account.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
interface Position {
account: string
deposits: import('@cosmjs/stargate').Coin[]
debts: import('@cosmjs/stargate').Coin[]
lends: import('@cosmjs/stargate').Coin[]
}

View File

@ -18,7 +18,7 @@ interface OtherAsset extends Omit<Asset, 'symbol'> {
interface BorrowAsset {
denom: string
borrowRate: string | null
borrowRate: number | null
liquidity: {
amount: string
value: string

9
src/types/interfaces/market.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
interface Market {
denom: string
borrowRate: number
debtTotalScaled: number
collateralTotalScaled: number
depositEnabled: boolean
borrowEnabled: boolean
depositCap: number
}

View File

@ -1,4 +1,11 @@
interface Market {
interface PositionResponse {
account_id: string
deposits: Coin[]
debts: Coin[]
lends: Coin[]
}
interface MarketResponse {
denom: string
max_loan_to_value: string
liquidation_threshold: string
@ -21,11 +28,3 @@ interface Market {
borrow_enabled: boolean
deposit_cap: string
}
interface MarketResult {
wasm: MarketData
}
interface MarketData {
[key: string]: Market
}

View File

@ -11,13 +11,12 @@ export async function callAPI<T>(endpoint: string): Promise<T> {
}
export async function getBorrowData() {
await sleep()
return callAPI<BorrowAsset[]>('/markets/borrow')
}
export async function getCreditAccounts(address: string) {
if (!address) return []
return callAPI<any[]>(`/wallets/${address}/accounts`)
return callAPI<string[]>(`/wallets/${address}/accounts`)
}
export async function getMarkets() {
@ -41,11 +40,13 @@ export async function getAccountDeposits(account: string) {
if (!account) return []
return callAPI<Coin[]>(`/accounts/${account}/deposits`)
}
export async function getWalletBalances(wallet: string) {
if (!wallet) return []
return callAPI<Coin[]>(`/wallets/${wallet}/balances`)
}
async function sleep() {
return new Promise((resolve) => setTimeout(resolve, 2500))
export async function getAccountsPositions(wallet: string) {
if (!wallet) return []
return callAPI<Position[]>(`/wallets/${wallet}/accounts/positions`)
}

24
src/utils/resolvers.ts Normal file
View File

@ -0,0 +1,24 @@
export function resolvePositionResponses(responses: PositionResponse[]): Position[] {
return responses.map(resolvePositionResponse)
}
export function resolvePositionResponse(response: PositionResponse): Position {
return {
account: response.account_id,
deposits: response.deposits,
debts: response.debts,
lends: response.lends,
}
}
export function resolveMarketResponses(responses: MarketResponse[]): Market[] {
return responses.map((response) => ({
denom: response.denom,
borrowRate: Number(response.borrow_rate),
debtTotalScaled: Number(response.debt_total_scaled),
collateralTotalScaled: Number(response.collateral_total_scaled),
depositEnabled: response.deposit_enabled,
borrowEnabled: response.borrow_enabled,
depositCap: Number(response.deposit_cap),
}))
}