From 1177d94153edba2671e393b2aacc07d86a70265c Mon Sep 17 00:00:00 2001 From: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com> Date: Wed, 6 Jan 2021 10:43:00 -0600 Subject: [PATCH] feat: update layout --- src/components/ReserveStatus/index.tsx | 4 +- .../ReserveUtilizationChart/index.tsx | 4 +- src/components/SideReserveOverview/index.tsx | 2 +- src/constants/math.ts | 1 + src/contexts/lending.tsx | 7 +- src/hooks/useCollateralBalance.ts | 2 +- src/models/lending/borrow.ts | 6 +- src/models/lending/deposit.ts | 11 +-- src/models/lending/reserve.ts | 86 ++++++++++++------- src/views/home/index.tsx | 2 +- src/views/home/item.tsx | 4 +- 11 files changed, 79 insertions(+), 50 deletions(-) diff --git a/src/components/ReserveStatus/index.tsx b/src/components/ReserveStatus/index.tsx index a8e91cc..5341535 100644 --- a/src/components/ReserveStatus/index.tsx +++ b/src/components/ReserveStatus/index.tsx @@ -26,7 +26,7 @@ export const ReserveStatus = (props: { const liquidityMint = useMint(mintAddress); const { price } = useMidPriceInUSD(mintAddress); const availableLiquidity = fromLamports( - props.reserve.availableLiquidity.toNumber(), + props.reserve.state.availableLiquidity, liquidityMint ); @@ -35,7 +35,7 @@ export const ReserveStatus = (props: { const totalBorrows = useMemo( () => fromLamports( - wadToLamports(props.reserve.borrowedLiquidityWad), + wadToLamports(props.reserve.state.borrowedLiquidityWad), liquidityMint ), [props.reserve, liquidityMint] diff --git a/src/components/ReserveUtilizationChart/index.tsx b/src/components/ReserveUtilizationChart/index.tsx index 2962fa0..35c5aed 100644 --- a/src/components/ReserveUtilizationChart/index.tsx +++ b/src/components/ReserveUtilizationChart/index.tsx @@ -9,14 +9,14 @@ export const ReserveUtilizationChart = (props: { reserve: LendingReserve }) => { const mintAddress = props.reserve.liquidityMint?.toBase58(); const liquidityMint = useMint(mintAddress); const availableLiquidity = fromLamports( - props.reserve.availableLiquidity.toNumber(), + props.reserve.state.availableLiquidity, liquidityMint ); const totalBorrows = useMemo( () => fromLamports( - wadToLamports(props.reserve.borrowedLiquidityWad), + wadToLamports(props.reserve.state.borrowedLiquidityWad), liquidityMint ), [props.reserve, liquidityMint] diff --git a/src/components/SideReserveOverview/index.tsx b/src/components/SideReserveOverview/index.tsx index f7acc5f..f60518c 100644 --- a/src/components/SideReserveOverview/index.tsx +++ b/src/components/SideReserveOverview/index.tsx @@ -31,7 +31,7 @@ export const SideReserveOverview = (props: { const liquidityMint = useMint(reserve.liquidityMint); const availableLiquidity = fromLamports( - reserve.availableLiquidity.toNumber(), + reserve.state.availableLiquidity, liquidityMint ); diff --git a/src/constants/math.ts b/src/constants/math.ts index 53fe6af..d0b4865 100644 --- a/src/constants/math.ts +++ b/src/constants/math.ts @@ -1,6 +1,7 @@ import BN from "bn.js"; export const TEN = new BN(10); +export const HALF_WAD = TEN.pow(new BN(18)); export const WAD = TEN.pow(new BN(18)); export const RAY = TEN.pow(new BN(27)); export const ZERO = new BN(0); diff --git a/src/contexts/lending.tsx b/src/contexts/lending.tsx index 0a3e02d..8768d2a 100644 --- a/src/contexts/lending.tsx +++ b/src/contexts/lending.tsx @@ -11,7 +11,7 @@ import { LendingObligationParser, } from './../models/lending'; import { cache, getMultipleAccounts, MintParser, ParsedAccount } from './accounts'; -import { PublicKey } from '@solana/web3.js'; +import { PublicKey, AccountInfo } from '@solana/web3.js'; import { DexMarketParser } from '../models/dex'; import { usePrecacheMarket } from './market'; import { useLendingReserves } from '../hooks'; @@ -41,7 +41,10 @@ export const useLending = () => { // TODO: query for all the dex from reserves - const processAccount = useCallback((item) => { + const processAccount = useCallback((item : { pubkey: PublicKey, account: AccountInfo }) => { + + console.log('Account length: ', item.account.data.length); + if (isLendingReserve(item.account)) { const reserve = cache.add(item.pubkey.toBase58(), item.account, LendingReserveParser); diff --git a/src/hooks/useCollateralBalance.ts b/src/hooks/useCollateralBalance.ts index a3d5cb7..6f6a74e 100644 --- a/src/hooks/useCollateralBalance.ts +++ b/src/hooks/useCollateralBalance.ts @@ -57,6 +57,6 @@ export function calculateCollateralBalance( reserve: LendingReserve, balanceLamports: number) { return reserveMarketCap(reserve) * - (balanceLamports / (reserve?.collateralMintSupply.toNumber() || 1)); + (balanceLamports / (reserve?.state.collateralMintSupply.toNumber() || 1)); } diff --git a/src/models/lending/borrow.ts b/src/models/lending/borrow.ts index 87c7ec7..94874de 100644 --- a/src/models/lending/borrow.ts +++ b/src/models/lending/borrow.ts @@ -2,10 +2,9 @@ import { PublicKey, SYSVAR_CLOCK_PUBKEY, SYSVAR_RENT_PUBKEY, TransactionInstruct import BN from 'bn.js'; import * as BufferLayout from 'buffer-layout'; import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; -import { wadToLamports } from '../../utils/utils'; import * as Layout from './../../utils/layout'; import { LendingInstruction } from './lending'; -import { LendingReserve } from './reserve'; +import { calculateUtilizationRatio, LendingReserve } from './reserve'; export enum BorrowAmountType { LiquidityBorrowAmount = 0, @@ -116,8 +115,7 @@ export const borrowInstruction = ( // deposit APY utilization currentUtilizationRate * borrowAPY export const calculateBorrowAPY = (reserve: LendingReserve) => { - const totalBorrows = wadToLamports(reserve.borrowedLiquidityWad).toNumber(); - const currentUtilization = totalBorrows / (reserve.availableLiquidity.toNumber() + totalBorrows); + const currentUtilization = calculateUtilizationRatio(reserve); const optimalUtilization = reserve.config.optimalUtilizationRate / 100; let borrowAPY; diff --git a/src/models/lending/deposit.ts b/src/models/lending/deposit.ts index b820db9..b715a41 100644 --- a/src/models/lending/deposit.ts +++ b/src/models/lending/deposit.ts @@ -2,11 +2,10 @@ import { PublicKey, SYSVAR_CLOCK_PUBKEY, TransactionInstruction } from '@solana/ import BN from 'bn.js'; import * as BufferLayout from 'buffer-layout'; import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; -import { wadToLamports } from '../../utils/utils'; import * as Layout from './../../utils/layout'; import { calculateBorrowAPY } from './borrow'; import { LendingInstruction } from './lending'; -import { LendingReserve } from './reserve'; +import { calculateUtilizationRatio, LendingReserve } from './reserve'; /// Deposit liquidity into a reserve. The output is a collateral token representing ownership /// of the reserve liquidity pool. @@ -32,7 +31,10 @@ export const depositInstruction = ( reserveSupply: PublicKey, collateralMint: PublicKey ): TransactionInstruction => { - const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction'), Layout.uint64('liquidityAmount')]); + const dataLayout = BufferLayout.struct([ + BufferLayout.u8('instruction'), + Layout.uint64('liquidityAmount') + ]); const data = Buffer.alloc(dataLayout.span); dataLayout.encode( @@ -63,8 +65,7 @@ export const depositInstruction = ( }; export const calculateDepositAPY = (reserve: LendingReserve) => { - const totalBorrows = wadToLamports(reserve.borrowedLiquidityWad).toNumber(); - const currentUtilization = totalBorrows / (reserve.availableLiquidity.toNumber() + totalBorrows); + const currentUtilization = calculateUtilizationRatio(reserve); const borrowAPY = calculateBorrowAPY(reserve); return currentUtilization * borrowAPY; diff --git a/src/models/lending/reserve.ts b/src/models/lending/reserve.ts index 3c654ab..9b637a6 100644 --- a/src/models/lending/reserve.ts +++ b/src/models/lending/reserve.ts @@ -7,23 +7,38 @@ import { } from '@solana/web3.js'; import BN from 'bn.js'; import * as BufferLayout from 'buffer-layout'; +import { HALF_WAD } from '../../constants'; import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; import { wadToLamports } from '../../utils/utils'; import * as Layout from './../../utils/layout'; import { LendingInstruction } from './lending'; export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct([ - Layout.uint64('lastUpdateSlot'), + Layout.publicKey('lendingMarket'), Layout.publicKey('liquidityMint'), BufferLayout.u8('liquidityMintDecimals'), Layout.publicKey('liquiditySupply'), Layout.publicKey('collateralMint'), Layout.publicKey('collateralSupply'), + + Layout.publicKey('collateralFeesReceiver'), + // TODO: replace u32 option with generic quivalent BufferLayout.u32('dexMarketOption'), Layout.publicKey('dexMarket'), + BufferLayout.struct( + [ + Layout.uint64('lastUpdateSlot'), + Layout.uint128('cumulativeBorrowRateWad'), + Layout.uint128('borrowedLiquidityWad'), + Layout.uint64('availableLiquidity'), + Layout.uint64('collateralMintSupply'), + ], + 'state' + ), + BufferLayout.struct( [ /// Optimal utilization rate as a percent @@ -41,39 +56,40 @@ export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout. /// Max borrow APY BufferLayout.u8('maxBorrowRate'), - /// Fee assessed on `BorrowReserveLiquidity`, expressed as a Wad. - /// Must be between 0 and 10^18, such that 10^18 = 1. A few examples for - /// clarity: - /// 1% = 10_000_000_000_000_000 - /// 0.01% (1 basis point) = 100_000_000_000_000 - /// 0.00001% (Aave borrow fee) = 100_000_000_000 - BufferLayout.uint64('borrowFeeWad'), + BufferLayout.struct( + [ + /// Fee assessed on `BorrowReserveLiquidity`, expressed as a Wad. + /// Must be between 0 and 10^18, such that 10^18 = 1. A few examples for + /// clarity: + /// 1% = 10_000_000_000_000_000 + /// 0.01% (1 basis point) = 100_000_000_000_000 + /// 0.00001% (Aave borrow fee) = 100_000_000_000 + Layout.uint64('borrowFeeWad'), - /// Amount of fee going to host account, if provided in liquidate and repay - BufferLayout.u8('hostFeePercentage'), + /// Amount of fee going to host account, if provided in liquidate and repay + BufferLayout.u8('hostFeePercentage'), + ], + 'fees' + ), ], 'config' ), - Layout.uint128('cumulativeBorrowRateWad'), - Layout.uint128('borrowedLiquidityWad'), - - Layout.uint64('availableLiquidity'), - Layout.uint64('collateralMintSupply'), ]); export const isLendingReserve = (info: AccountInfo) => { + console.log('Lending Reserve: ', LendingReserveLayout.span) return info.data.length === LendingReserveLayout.span; }; export interface LendingReserve { - lastUpdateSlot: BN; lendingMarket: PublicKey; liquiditySupply: PublicKey; liquidityMint: PublicKey; - collateralSupply: PublicKey; collateralMint: PublicKey; + collateralSupply: PublicKey; + collateralFeesReceiver: PublicKey; dexMarketOption: number; dexMarket: PublicKey; @@ -87,21 +103,27 @@ export interface LendingReserve { optimalBorrowRate: number; maxBorrowRate: number; - borrowFeeWad: BN; - hostFeePercentage: number; + fees: { + borrowFeeWad: BN; + hostFeePercentage: number; + }; }; - cumulativeBorrowRateWad: BN; - borrowedLiquidityWad: BN; + state: { + lastUpdateSlot: BN; + cumulativeBorrowRateWad: BN; + borrowedLiquidityWad: BN; - availableLiquidity: BN; - collateralMintSupply: BN; + availableLiquidity: BN; + collateralMintSupply: BN; + }; } export const LendingReserveParser = (pubKey: PublicKey, info: AccountInfo) => { const buffer = Buffer.from(info.data); - const data = LendingReserveLayout.decode(buffer); - if (data.lastUpdateSlot.toNumber() === 0) return; + const data = LendingReserveLayout.decode(buffer) as LendingReserve; + + if (data.state.lastUpdateSlot.toNumber() === 0) return; const details = { pubkey: pubKey, @@ -111,6 +133,8 @@ export const LendingReserveParser = (pubKey: PublicKey, info: AccountInfo { - let borrowedLiquidity = wadToLamports(reserve.borrowedLiquidityWad).toNumber(); - return borrowedLiquidity / (reserve.availableLiquidity.toNumber() + borrowedLiquidity); + const totalBorrows = wadToLamports(reserve.state.borrowedLiquidityWad).toNumber(); + const currentUtilization = totalBorrows / (reserve.state.availableLiquidity.toNumber() + totalBorrows); + + return currentUtilization; }; export const reserveMarketCap = (reserve?: LendingReserve) => { - const available = reserve?.availableLiquidity.toNumber() || 0; - const borrowed = wadToLamports(reserve?.borrowedLiquidityWad).toNumber(); + const available = reserve?.state.availableLiquidity.toNumber() || 0; + const borrowed = wadToLamports(reserve?.state.borrowedLiquidityWad).toNumber(); const total = available + borrowed; return total; }; export const collateralExchangeRate = (reserve?: LendingReserve) => { - return (reserve?.collateralMintSupply.toNumber() || 1) / reserveMarketCap(reserve); + return (reserve?.state.collateralMintSupply.toNumber() || 1) / reserveMarketCap(reserve); }; export const collateralToLiquidity = (collateralAmount: BN | number, reserve?: LendingReserve) => { diff --git a/src/views/home/index.tsx b/src/views/home/index.tsx index 0377e74..1c079b8 100644 --- a/src/views/home/index.tsx +++ b/src/views/home/index.tsx @@ -51,7 +51,7 @@ export const HomeView = () => { marketSize: fromLamports(marketCapLamports, liquidityMint?.info) * price, borrowed: fromLamports( - wadToLamports(item.info?.borrowedLiquidityWad).toNumber(), + wadToLamports(item.info?.state.borrowedLiquidityWad).toNumber(), liquidityMint.info ) * price, diff --git a/src/views/home/item.tsx b/src/views/home/item.tsx index f14adfa..a6f1e75 100644 --- a/src/views/home/item.tsx +++ b/src/views/home/item.tsx @@ -27,14 +27,14 @@ export const LendingReserveItem = (props: { const liquidityMint = useMint(props.reserve.liquidityMint); const availableLiquidity = fromLamports( - props.reserve.availableLiquidity.toNumber(), + props.reserve.state.availableLiquidity, liquidityMint ); const totalBorrows = useMemo( () => fromLamports( - wadToLamports(props.reserve.borrowedLiquidityWad), + wadToLamports(props.reserve.state.borrowedLiquidityWad), liquidityMint ), [props.reserve, liquidityMint]