feat: update layout

This commit is contained in:
bartosz-lipinski 2021-01-06 10:43:00 -06:00
parent a2154ff63c
commit 1177d94153
11 changed files with 79 additions and 50 deletions

View File

@ -26,7 +26,7 @@ export const ReserveStatus = (props: {
const liquidityMint = useMint(mintAddress); const liquidityMint = useMint(mintAddress);
const { price } = useMidPriceInUSD(mintAddress); const { price } = useMidPriceInUSD(mintAddress);
const availableLiquidity = fromLamports( const availableLiquidity = fromLamports(
props.reserve.availableLiquidity.toNumber(), props.reserve.state.availableLiquidity,
liquidityMint liquidityMint
); );
@ -35,7 +35,7 @@ export const ReserveStatus = (props: {
const totalBorrows = useMemo( const totalBorrows = useMemo(
() => () =>
fromLamports( fromLamports(
wadToLamports(props.reserve.borrowedLiquidityWad), wadToLamports(props.reserve.state.borrowedLiquidityWad),
liquidityMint liquidityMint
), ),
[props.reserve, liquidityMint] [props.reserve, liquidityMint]

View File

@ -9,14 +9,14 @@ export const ReserveUtilizationChart = (props: { reserve: LendingReserve }) => {
const mintAddress = props.reserve.liquidityMint?.toBase58(); const mintAddress = props.reserve.liquidityMint?.toBase58();
const liquidityMint = useMint(mintAddress); const liquidityMint = useMint(mintAddress);
const availableLiquidity = fromLamports( const availableLiquidity = fromLamports(
props.reserve.availableLiquidity.toNumber(), props.reserve.state.availableLiquidity,
liquidityMint liquidityMint
); );
const totalBorrows = useMemo( const totalBorrows = useMemo(
() => () =>
fromLamports( fromLamports(
wadToLamports(props.reserve.borrowedLiquidityWad), wadToLamports(props.reserve.state.borrowedLiquidityWad),
liquidityMint liquidityMint
), ),
[props.reserve, liquidityMint] [props.reserve, liquidityMint]

View File

@ -31,7 +31,7 @@ export const SideReserveOverview = (props: {
const liquidityMint = useMint(reserve.liquidityMint); const liquidityMint = useMint(reserve.liquidityMint);
const availableLiquidity = fromLamports( const availableLiquidity = fromLamports(
reserve.availableLiquidity.toNumber(), reserve.state.availableLiquidity,
liquidityMint liquidityMint
); );

View File

@ -1,6 +1,7 @@
import BN from "bn.js"; import BN from "bn.js";
export const TEN = new BN(10); 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 WAD = TEN.pow(new BN(18));
export const RAY = TEN.pow(new BN(27)); export const RAY = TEN.pow(new BN(27));
export const ZERO = new BN(0); export const ZERO = new BN(0);

View File

@ -11,7 +11,7 @@ import {
LendingObligationParser, LendingObligationParser,
} from './../models/lending'; } from './../models/lending';
import { cache, getMultipleAccounts, MintParser, ParsedAccount } from './accounts'; 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 { DexMarketParser } from '../models/dex';
import { usePrecacheMarket } from './market'; import { usePrecacheMarket } from './market';
import { useLendingReserves } from '../hooks'; import { useLendingReserves } from '../hooks';
@ -41,7 +41,10 @@ export const useLending = () => {
// TODO: query for all the dex from reserves // TODO: query for all the dex from reserves
const processAccount = useCallback((item) => { const processAccount = useCallback((item : { pubkey: PublicKey, account: AccountInfo<Buffer> }) => {
console.log('Account length: ', item.account.data.length);
if (isLendingReserve(item.account)) { if (isLendingReserve(item.account)) {
const reserve = cache.add(item.pubkey.toBase58(), item.account, LendingReserveParser); const reserve = cache.add(item.pubkey.toBase58(), item.account, LendingReserveParser);

View File

@ -57,6 +57,6 @@ export function calculateCollateralBalance(
reserve: LendingReserve, reserve: LendingReserve,
balanceLamports: number) { balanceLamports: number) {
return reserveMarketCap(reserve) * return reserveMarketCap(reserve) *
(balanceLamports / (reserve?.collateralMintSupply.toNumber() || 1)); (balanceLamports / (reserve?.state.collateralMintSupply.toNumber() || 1));
} }

View File

@ -2,10 +2,9 @@ import { PublicKey, SYSVAR_CLOCK_PUBKEY, SYSVAR_RENT_PUBKEY, TransactionInstruct
import BN from 'bn.js'; import BN from 'bn.js';
import * as BufferLayout from 'buffer-layout'; import * as BufferLayout from 'buffer-layout';
import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids';
import { wadToLamports } from '../../utils/utils';
import * as Layout from './../../utils/layout'; import * as Layout from './../../utils/layout';
import { LendingInstruction } from './lending'; import { LendingInstruction } from './lending';
import { LendingReserve } from './reserve'; import { calculateUtilizationRatio, LendingReserve } from './reserve';
export enum BorrowAmountType { export enum BorrowAmountType {
LiquidityBorrowAmount = 0, LiquidityBorrowAmount = 0,
@ -116,8 +115,7 @@ export const borrowInstruction = (
// deposit APY utilization currentUtilizationRate * borrowAPY // deposit APY utilization currentUtilizationRate * borrowAPY
export const calculateBorrowAPY = (reserve: LendingReserve) => { export const calculateBorrowAPY = (reserve: LendingReserve) => {
const totalBorrows = wadToLamports(reserve.borrowedLiquidityWad).toNumber(); const currentUtilization = calculateUtilizationRatio(reserve);
const currentUtilization = totalBorrows / (reserve.availableLiquidity.toNumber() + totalBorrows);
const optimalUtilization = reserve.config.optimalUtilizationRate / 100; const optimalUtilization = reserve.config.optimalUtilizationRate / 100;
let borrowAPY; let borrowAPY;

View File

@ -2,11 +2,10 @@ import { PublicKey, SYSVAR_CLOCK_PUBKEY, TransactionInstruction } from '@solana/
import BN from 'bn.js'; import BN from 'bn.js';
import * as BufferLayout from 'buffer-layout'; import * as BufferLayout from 'buffer-layout';
import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids';
import { wadToLamports } from '../../utils/utils';
import * as Layout from './../../utils/layout'; import * as Layout from './../../utils/layout';
import { calculateBorrowAPY } from './borrow'; import { calculateBorrowAPY } from './borrow';
import { LendingInstruction } from './lending'; 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 /// Deposit liquidity into a reserve. The output is a collateral token representing ownership
/// of the reserve liquidity pool. /// of the reserve liquidity pool.
@ -32,7 +31,10 @@ export const depositInstruction = (
reserveSupply: PublicKey, reserveSupply: PublicKey,
collateralMint: PublicKey collateralMint: PublicKey
): TransactionInstruction => { ): 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); const data = Buffer.alloc(dataLayout.span);
dataLayout.encode( dataLayout.encode(
@ -63,8 +65,7 @@ export const depositInstruction = (
}; };
export const calculateDepositAPY = (reserve: LendingReserve) => { export const calculateDepositAPY = (reserve: LendingReserve) => {
const totalBorrows = wadToLamports(reserve.borrowedLiquidityWad).toNumber(); const currentUtilization = calculateUtilizationRatio(reserve);
const currentUtilization = totalBorrows / (reserve.availableLiquidity.toNumber() + totalBorrows);
const borrowAPY = calculateBorrowAPY(reserve); const borrowAPY = calculateBorrowAPY(reserve);
return currentUtilization * borrowAPY; return currentUtilization * borrowAPY;

View File

@ -7,23 +7,38 @@ import {
} from '@solana/web3.js'; } from '@solana/web3.js';
import BN from 'bn.js'; import BN from 'bn.js';
import * as BufferLayout from 'buffer-layout'; import * as BufferLayout from 'buffer-layout';
import { HALF_WAD } from '../../constants';
import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids';
import { wadToLamports } from '../../utils/utils'; import { wadToLamports } from '../../utils/utils';
import * as Layout from './../../utils/layout'; import * as Layout from './../../utils/layout';
import { LendingInstruction } from './lending'; import { LendingInstruction } from './lending';
export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct([ export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct([
Layout.uint64('lastUpdateSlot'),
Layout.publicKey('lendingMarket'), Layout.publicKey('lendingMarket'),
Layout.publicKey('liquidityMint'), Layout.publicKey('liquidityMint'),
BufferLayout.u8('liquidityMintDecimals'), BufferLayout.u8('liquidityMintDecimals'),
Layout.publicKey('liquiditySupply'), Layout.publicKey('liquiditySupply'),
Layout.publicKey('collateralMint'), Layout.publicKey('collateralMint'),
Layout.publicKey('collateralSupply'), Layout.publicKey('collateralSupply'),
Layout.publicKey('collateralFeesReceiver'),
// TODO: replace u32 option with generic quivalent // TODO: replace u32 option with generic quivalent
BufferLayout.u32('dexMarketOption'), BufferLayout.u32('dexMarketOption'),
Layout.publicKey('dexMarket'), Layout.publicKey('dexMarket'),
BufferLayout.struct(
[
Layout.uint64('lastUpdateSlot'),
Layout.uint128('cumulativeBorrowRateWad'),
Layout.uint128('borrowedLiquidityWad'),
Layout.uint64('availableLiquidity'),
Layout.uint64('collateralMintSupply'),
],
'state'
),
BufferLayout.struct( BufferLayout.struct(
[ [
/// Optimal utilization rate as a percent /// Optimal utilization rate as a percent
@ -41,39 +56,40 @@ export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.
/// Max borrow APY /// Max borrow APY
BufferLayout.u8('maxBorrowRate'), BufferLayout.u8('maxBorrowRate'),
/// Fee assessed on `BorrowReserveLiquidity`, expressed as a Wad. BufferLayout.struct(
/// Must be between 0 and 10^18, such that 10^18 = 1. A few examples for [
/// clarity: /// Fee assessed on `BorrowReserveLiquidity`, expressed as a Wad.
/// 1% = 10_000_000_000_000_000 /// Must be between 0 and 10^18, such that 10^18 = 1. A few examples for
/// 0.01% (1 basis point) = 100_000_000_000_000 /// clarity:
/// 0.00001% (Aave borrow fee) = 100_000_000_000 /// 1% = 10_000_000_000_000_000
BufferLayout.uint64('borrowFeeWad'), /// 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 /// Amount of fee going to host account, if provided in liquidate and repay
BufferLayout.u8('hostFeePercentage'), BufferLayout.u8('hostFeePercentage'),
],
'fees'
),
], ],
'config' 'config'
), ),
Layout.uint128('cumulativeBorrowRateWad'),
Layout.uint128('borrowedLiquidityWad'),
Layout.uint64('availableLiquidity'),
Layout.uint64('collateralMintSupply'),
]); ]);
export const isLendingReserve = (info: AccountInfo<Buffer>) => { export const isLendingReserve = (info: AccountInfo<Buffer>) => {
console.log('Lending Reserve: ', LendingReserveLayout.span)
return info.data.length === LendingReserveLayout.span; return info.data.length === LendingReserveLayout.span;
}; };
export interface LendingReserve { export interface LendingReserve {
lastUpdateSlot: BN;
lendingMarket: PublicKey; lendingMarket: PublicKey;
liquiditySupply: PublicKey; liquiditySupply: PublicKey;
liquidityMint: PublicKey; liquidityMint: PublicKey;
collateralSupply: PublicKey;
collateralMint: PublicKey; collateralMint: PublicKey;
collateralSupply: PublicKey;
collateralFeesReceiver: PublicKey;
dexMarketOption: number; dexMarketOption: number;
dexMarket: PublicKey; dexMarket: PublicKey;
@ -87,21 +103,27 @@ export interface LendingReserve {
optimalBorrowRate: number; optimalBorrowRate: number;
maxBorrowRate: number; maxBorrowRate: number;
borrowFeeWad: BN; fees: {
hostFeePercentage: number; borrowFeeWad: BN;
hostFeePercentage: number;
};
}; };
cumulativeBorrowRateWad: BN; state: {
borrowedLiquidityWad: BN; lastUpdateSlot: BN;
cumulativeBorrowRateWad: BN;
borrowedLiquidityWad: BN;
availableLiquidity: BN; availableLiquidity: BN;
collateralMintSupply: BN; collateralMintSupply: BN;
};
} }
export const LendingReserveParser = (pubKey: PublicKey, info: AccountInfo<Buffer>) => { export const LendingReserveParser = (pubKey: PublicKey, info: AccountInfo<Buffer>) => {
const buffer = Buffer.from(info.data); const buffer = Buffer.from(info.data);
const data = LendingReserveLayout.decode(buffer); const data = LendingReserveLayout.decode(buffer) as LendingReserve;
if (data.lastUpdateSlot.toNumber() === 0) return;
if (data.state.lastUpdateSlot.toNumber() === 0) return;
const details = { const details = {
pubkey: pubKey, pubkey: pubKey,
@ -111,6 +133,8 @@ export const LendingReserveParser = (pubKey: PublicKey, info: AccountInfo<Buffer
info: data, info: data,
}; };
return details; return details;
}; };
@ -176,20 +200,22 @@ export const initReserveInstruction = (
}; };
export const calculateUtilizationRatio = (reserve: LendingReserve) => { export const calculateUtilizationRatio = (reserve: LendingReserve) => {
let borrowedLiquidity = wadToLamports(reserve.borrowedLiquidityWad).toNumber(); const totalBorrows = wadToLamports(reserve.state.borrowedLiquidityWad).toNumber();
return borrowedLiquidity / (reserve.availableLiquidity.toNumber() + borrowedLiquidity); const currentUtilization = totalBorrows / (reserve.state.availableLiquidity.toNumber() + totalBorrows);
return currentUtilization;
}; };
export const reserveMarketCap = (reserve?: LendingReserve) => { export const reserveMarketCap = (reserve?: LendingReserve) => {
const available = reserve?.availableLiquidity.toNumber() || 0; const available = reserve?.state.availableLiquidity.toNumber() || 0;
const borrowed = wadToLamports(reserve?.borrowedLiquidityWad).toNumber(); const borrowed = wadToLamports(reserve?.state.borrowedLiquidityWad).toNumber();
const total = available + borrowed; const total = available + borrowed;
return total; return total;
}; };
export const collateralExchangeRate = (reserve?: LendingReserve) => { 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) => { export const collateralToLiquidity = (collateralAmount: BN | number, reserve?: LendingReserve) => {

View File

@ -51,7 +51,7 @@ export const HomeView = () => {
marketSize: fromLamports(marketCapLamports, liquidityMint?.info) * marketSize: fromLamports(marketCapLamports, liquidityMint?.info) *
price, price,
borrowed: fromLamports( borrowed: fromLamports(
wadToLamports(item.info?.borrowedLiquidityWad).toNumber(), wadToLamports(item.info?.state.borrowedLiquidityWad).toNumber(),
liquidityMint.info liquidityMint.info
) * ) *
price, price,

View File

@ -27,14 +27,14 @@ export const LendingReserveItem = (props: {
const liquidityMint = useMint(props.reserve.liquidityMint); const liquidityMint = useMint(props.reserve.liquidityMint);
const availableLiquidity = fromLamports( const availableLiquidity = fromLamports(
props.reserve.availableLiquidity.toNumber(), props.reserve.state.availableLiquidity,
liquidityMint liquidityMint
); );
const totalBorrows = useMemo( const totalBorrows = useMemo(
() => () =>
fromLamports( fromLamports(
wadToLamports(props.reserve.borrowedLiquidityWad), wadToLamports(props.reserve.state.borrowedLiquidityWad),
liquidityMint liquidityMint
), ),
[props.reserve, liquidityMint] [props.reserve, liquidityMint]