feat: borrow instruction
This commit is contained in:
parent
3554e8ce86
commit
42af776ee8
|
@ -44,6 +44,31 @@ export function ensureSplAccount(
|
|||
return account;
|
||||
}
|
||||
|
||||
export const DEFAULT_TEMP_MEM_SPACE = 65528;
|
||||
|
||||
export function createTempMemoryAccount(
|
||||
instructions: TransactionInstruction[],
|
||||
payer: PublicKey,
|
||||
signers: Account[],
|
||||
space = DEFAULT_TEMP_MEM_SPACE) {
|
||||
const account = new Account();
|
||||
instructions.push(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: payer,
|
||||
newAccountPubkey: account.publicKey,
|
||||
// 0 will evict/clost account since it cannot pay rent
|
||||
lamports: 0,
|
||||
space: space,
|
||||
programId: TOKEN_PROGRAM_ID,
|
||||
})
|
||||
);
|
||||
|
||||
signers.push(account);
|
||||
|
||||
return account.publicKey;
|
||||
}
|
||||
|
||||
|
||||
export function createUninitializedAccount(
|
||||
instructions: TransactionInstruction[],
|
||||
payer: PublicKey,
|
||||
|
|
|
@ -9,10 +9,11 @@ import { notify } from "../utils/notifications";
|
|||
import { LendingReserve } from "./../models/lending/reserve";
|
||||
import { AccountLayout, MintInfo, MintLayout, Token } from "@solana/spl-token";
|
||||
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../constants/ids";
|
||||
import { createUninitializedAccount, ensureSplAccount, findOrCreateAccountByMint } from "./account";
|
||||
import { createTempMemoryAccount, createUninitializedAccount, ensureSplAccount, findOrCreateAccountByMint } from "./account";
|
||||
import { cache, MintParser, ParsedAccount } from "../contexts/accounts";
|
||||
import { TokenAccount, LendingObligationLayout, borrowInstruction, LendingMarket } from "../models";
|
||||
import { toLamports } from "../utils/utils";
|
||||
import { DexMarketParser } from "../models/dex";
|
||||
|
||||
export const borrow = async (
|
||||
from: TokenAccount,
|
||||
|
@ -33,14 +34,68 @@ export const borrow = async (
|
|||
type: "warn",
|
||||
});
|
||||
|
||||
const signers: Account[] = [];
|
||||
const instructions: TransactionInstruction[] = [];
|
||||
const cleanupInstructions: TransactionInstruction[] = [];
|
||||
let signers: Account[] = [];
|
||||
let instructions: TransactionInstruction[] = [];
|
||||
let cleanupInstructions: TransactionInstruction[] = [];
|
||||
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
AccountLayout.span
|
||||
);
|
||||
|
||||
const obligation = createUninitializedAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
await connection.getMinimumBalanceForRentExemption(
|
||||
LendingObligationLayout.span
|
||||
),
|
||||
signers,
|
||||
);
|
||||
|
||||
const obligationMint = createUninitializedAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
await connection.getMinimumBalanceForRentExemption(
|
||||
MintLayout.span
|
||||
),
|
||||
signers,
|
||||
);
|
||||
|
||||
const obligationTokenOutput = createUninitializedAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
signers,
|
||||
);
|
||||
|
||||
let toAccount = await findOrCreateAccountByMint(
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
accountRentExempt,
|
||||
borrowReserve.liquidityMint,
|
||||
signers
|
||||
);
|
||||
|
||||
// create all accounts in one transaction
|
||||
let tx = await sendTransaction(connection, wallet, instructions, [...signers]);
|
||||
|
||||
notify({
|
||||
message: "Obligation accounts created",
|
||||
description: `Transaction ${tx}`,
|
||||
type: "success",
|
||||
});
|
||||
|
||||
notify({
|
||||
message: "Adding Liquidity...",
|
||||
description: "Please review transactions to approve.",
|
||||
type: "warn",
|
||||
});
|
||||
|
||||
signers = [];
|
||||
instructions = [];
|
||||
cleanupInstructions = [];
|
||||
|
||||
const [authority] = await PublicKey.findProgramAddress(
|
||||
[depositReserve.lendingMarket.toBuffer()], // which account should be authority
|
||||
LENDING_PROGRAM_ID
|
||||
|
@ -70,56 +125,25 @@ export const borrow = async (
|
|||
)
|
||||
);
|
||||
|
||||
let toAccount = await findOrCreateAccountByMint(
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
accountRentExempt,
|
||||
borrowReserve.liquidityMint,
|
||||
signers
|
||||
);
|
||||
|
||||
const obligation = createUninitializedAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
await connection.getMinimumBalanceForRentExemption(
|
||||
LendingObligationLayout.span
|
||||
),
|
||||
signers,
|
||||
);
|
||||
|
||||
const obligationMint = createUninitializedAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
await connection.getMinimumBalanceForRentExemption(
|
||||
MintLayout.span
|
||||
),
|
||||
signers,
|
||||
);
|
||||
|
||||
const obligationTokenOutput = createUninitializedAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
signers,
|
||||
);
|
||||
|
||||
const market = cache.get(depositReserve.lendingMarket) as ParsedAccount<LendingMarket>;
|
||||
|
||||
|
||||
const dexMarketAddress = market.info.quoteMint.equals(borrowReserve.liquidityMint) ?
|
||||
borrowReserve.dexMarket :
|
||||
depositReserve.dexMarket;
|
||||
|
||||
const dexMarketAddress = borrowReserve.dexMarketOption ? borrowReserve.dexMarket : depositReserve.dexMarket;
|
||||
const dexMarket = cache.get(dexMarketAddress);
|
||||
debugger;
|
||||
|
||||
if(!dexMarket) {
|
||||
throw new Error(`Dex market doesn't exsists.`)
|
||||
}
|
||||
|
||||
const dexOrderBookSide = market.info.quoteMint.equals(borrowReserve.liquidityMint) ?
|
||||
dexMarket.info.bids :
|
||||
dexMarket.info.asks;
|
||||
const dexOrderBookSide = market.info.quoteMint.equals(depositReserve.liquidityMint) ?
|
||||
dexMarket?.info.bids :
|
||||
dexMarket?.info.asks
|
||||
|
||||
const memory = createTempMemoryAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
signers,
|
||||
);
|
||||
|
||||
// deposit
|
||||
instructions.push(
|
||||
|
@ -128,7 +152,7 @@ export const borrow = async (
|
|||
fromAccount,
|
||||
toAccount,
|
||||
depositReserveAddress,
|
||||
depositReserve.liquiditySupply,
|
||||
depositReserve.collateralSupply,
|
||||
borrowReserveAddress,
|
||||
borrowReserve.liquiditySupply,
|
||||
|
||||
|
@ -141,6 +165,8 @@ export const borrow = async (
|
|||
|
||||
dexMarketAddress,
|
||||
dexOrderBookSide,
|
||||
|
||||
memory,
|
||||
)
|
||||
);
|
||||
try {
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useCollateralBalance, useLendingReserve, useLendingReserves, useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import { useCollateralBalance, useLendingReserves, useTokenName, useUserBalance } from '../../hooks';
|
||||
import { LendingReserve, LendingReserveParser } from "../../models";
|
||||
import { TokenIcon } from "../TokenIcon";
|
||||
import { formatNumber, getTokenName } from "../../utils/utils";
|
||||
import { getTokenName } from "../../utils/utils";
|
||||
import { Button, Card, Select } from "antd";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { cache, ParsedAccount, useAccount } from "../../contexts/accounts";
|
||||
import { cache, ParsedAccount } from "../../contexts/accounts";
|
||||
import { NumericInput } from "../Input/numeric";
|
||||
import { useConnection, useConnectionConfig } from "../../contexts/connection";
|
||||
import { useWallet } from "../../contexts/wallet";
|
||||
import { borrow } from '../../actions';
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import './style.less';
|
||||
import { Token } from "@solana/spl-token";
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
|
@ -55,7 +54,6 @@ const CollateralSelector = (props: {
|
|||
export const BorrowInput = (props: { className?: string, reserve: LendingReserve, address: PublicKey }) => {
|
||||
const connection = useConnection();
|
||||
const { wallet } = useWallet();
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const [value, setValue] = useState('');
|
||||
|
||||
const borrowReserve = props.reserve;
|
||||
|
@ -71,26 +69,18 @@ export const BorrowInput = (props: { className?: string, reserve: LendingReserve
|
|||
return cache.get(id) as ParsedAccount<LendingReserve>;
|
||||
}, [collateralReserveMint])
|
||||
|
||||
const collateral = useCollateralBalance(collateralReserve?.info);
|
||||
|
||||
const name = useTokenName(borrowReserve?.liquidityMint);
|
||||
const {
|
||||
balance: tokenBalance,
|
||||
accounts: fromAccounts
|
||||
} = useUserBalance(collateralReserve?.info.collateralMint);
|
||||
// const collateralBalance = useUserBalance(reserve?.collateralMint);
|
||||
|
||||
if(collateral) {
|
||||
debugger;
|
||||
}
|
||||
|
||||
const onBorrow = useCallback(() => {
|
||||
if (!collateralReserve) {
|
||||
return;
|
||||
}
|
||||
|
||||
debugger;
|
||||
|
||||
borrow(
|
||||
fromAccounts[0],
|
||||
parseFloat(value),
|
||||
|
|
|
@ -42,6 +42,7 @@ export const DepositInput = (props: { className?: string, reserve: LendingReserv
|
|||
console.log(`liquidityMint: ${reserve.liquidityMint.toBase58()}`);
|
||||
console.log(`collateralSupply: ${reserve.collateralSupply.toBase58()}`);
|
||||
console.log(`collateralMint: ${reserve.collateralMint.toBase58()}`);
|
||||
console.log(`dexMarket: ${reserve.dexMarket.toBase58()}`);
|
||||
})();
|
||||
}, [reserve])
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ export interface ParsedAccountBase {
|
|||
export type AccountParser = (
|
||||
pubkey: PublicKey,
|
||||
data: AccountInfo<Buffer>
|
||||
) => ParsedAccountBase;
|
||||
) => ParsedAccountBase | undefined;
|
||||
|
||||
export interface ParsedAccount<T> extends ParsedAccountBase {
|
||||
info: T;
|
||||
|
@ -130,6 +130,10 @@ export const cache = {
|
|||
cache.registerParser(id, deserialize);
|
||||
pendingCalls.delete(address);
|
||||
const account = deserialize(new PublicKey(address), obj);
|
||||
if (!account) {
|
||||
return;
|
||||
}
|
||||
|
||||
genericCache.set(address, account);
|
||||
cache.emitter.raiseCacheUpdated(address, deserialize);
|
||||
return account;
|
||||
|
@ -146,8 +150,8 @@ export const cache = {
|
|||
},
|
||||
byParser: (parser: AccountParser) => {
|
||||
const result: string[] = [];
|
||||
for(const id of keyToAccountParser.keys()) {
|
||||
if(keyToAccountParser.get(id) === parser) {
|
||||
for (const id of keyToAccountParser.keys()) {
|
||||
if (keyToAccountParser.get(id) === parser) {
|
||||
result.push(id);
|
||||
}
|
||||
}
|
||||
|
@ -155,8 +159,12 @@ export const cache = {
|
|||
return result;
|
||||
},
|
||||
registerParser: (pubkey: PublicKey | string, parser: AccountParser) => {
|
||||
if (pubkey) {
|
||||
const address = typeof pubkey === 'string' ? pubkey : pubkey?.toBase58();
|
||||
keyToAccountParser.set(address, parser);
|
||||
}
|
||||
|
||||
return pubkey;
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -200,7 +208,7 @@ const UseNativeAccount = () => {
|
|||
|
||||
const updateCache = useCallback((account) => {
|
||||
const wrapped = wrapNativeAccount(wallet.publicKey, account);
|
||||
if(wrapped !== undefined && wallet) {
|
||||
if (wrapped !== undefined && wallet) {
|
||||
cache.registerParser(wallet.publicKey.toBase58(), TokenAccountParser);
|
||||
genericCache.set(wallet.publicKey.toBase58(), wrapped as TokenAccount);
|
||||
}
|
||||
|
@ -352,7 +360,7 @@ export const getMultipleAccounts = async (
|
|||
.map(
|
||||
(a) =>
|
||||
a.array.map((acc) => {
|
||||
if(!acc) {
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,16 +12,20 @@ import { notify } from "./../utils/notifications";
|
|||
import { ExplorerLink } from "../components/ExplorerLink";
|
||||
import LocalTokens from '../config/tokens.json';
|
||||
|
||||
export type ENV = "mainnet-beta" | "testnet" | "devnet" | "localnet";
|
||||
export type ENV = "mainnet-beta" | "testnet" | "devnet" | "localnet" | "lending";
|
||||
|
||||
export const ENDPOINTS = [
|
||||
{
|
||||
name: 'lending' as ENV,
|
||||
endpoint: "https://tln.solana.com",
|
||||
},
|
||||
{
|
||||
name: "mainnet-beta" as ENV,
|
||||
endpoint: "https://solana-api.projectserum.com/",
|
||||
},
|
||||
{ name: "testnet" as ENV, endpoint: clusterApiUrl("testnet") },
|
||||
{ name: "devnet" as ENV, endpoint: clusterApiUrl("devnet") },
|
||||
{ name: "localnet" as ENV, endpoint: "http://35.206.228.142:8899" },
|
||||
{ name: "localnet" as ENV, endpoint: "http://127.0.0.1:8899" },
|
||||
];
|
||||
|
||||
const DEFAULT = ENDPOINTS[0].endpoint;
|
||||
|
|
|
@ -2,8 +2,9 @@ import React, { useCallback, useEffect, useState } from "react";
|
|||
import { useConnection } from "./connection";
|
||||
import { LENDING_PROGRAM_ID } from "./../constants/ids";
|
||||
import { LendingMarketParser, isLendingReserve, isLendingMarket, LendingReserveParser, LendingReserve } from "./../models/lending";
|
||||
import { cache, getMultipleAccounts } from "./accounts";
|
||||
import { cache, getMultipleAccounts, MintParser, ParsedAccount } from "./accounts";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { DexMarketParser } from "../models/dex";
|
||||
|
||||
export interface LendingContextState {
|
||||
|
||||
|
@ -51,20 +52,25 @@ export const useLending = () => {
|
|||
|
||||
const toQuery = [
|
||||
...accounts.filter(acc => (acc?.info as LendingReserve).lendingMarket !== undefined)
|
||||
.map(acc => [
|
||||
(acc?.info as LendingReserve).collateralMint.toBase58(),
|
||||
(acc?.info as LendingReserve).liquidityMint.toBase58(),
|
||||
(acc?.info as LendingReserve).dexMarket.toBase58(),
|
||||
])
|
||||
].flat().filter((p) => p) as string[];
|
||||
.map(acc => acc as ParsedAccount<LendingReserve>)
|
||||
.map(acc => {
|
||||
const result = [
|
||||
cache.registerParser(acc?.info.collateralMint.toBase58(), MintParser),
|
||||
cache.registerParser(acc?.info.liquidityMint.toBase58(), MintParser),
|
||||
// ignore dex if its not set
|
||||
cache.registerParser(acc?.info.dexMarketOption ? acc?.info.dexMarket.toBase58() : '', DexMarketParser),
|
||||
].filter(_ => _);
|
||||
return result;
|
||||
})
|
||||
].flat() as string[];
|
||||
|
||||
// This will pre-cache all accounts used by pools
|
||||
// All those accounts are updated whenever there is a change
|
||||
await getMultipleAccounts(connection, toQuery, "single").then(
|
||||
({ keys, array }) => {
|
||||
return array.map((obj, index) => {
|
||||
// TODO: add to cache
|
||||
|
||||
const address = keys[index];
|
||||
cache.add(address, obj);
|
||||
return obj;
|
||||
}) as any[];
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ import { AccountInfo, Connection, PublicKey } from "@solana/web3.js";
|
|||
import { useMemo } from "react";
|
||||
import { EventEmitter } from "./../utils/eventEmitter";
|
||||
|
||||
import { DexMarketParser } from "./../models/dex";
|
||||
|
||||
export interface MarketsContextState {
|
||||
midPriceInUSD: (mint: string) => number;
|
||||
marketEmitter: EventEmitter;
|
||||
|
@ -39,7 +41,9 @@ export function MarketProvider({ children = null as any }) {
|
|||
]);
|
||||
|
||||
// TODO: identify which markets to query ...
|
||||
const mints = useMemo(() => [] as PublicKey[], []);
|
||||
const mints = useMemo(() => [
|
||||
|
||||
] as PublicKey[], []);
|
||||
|
||||
const marketByMint = useMemo(() => {
|
||||
return [
|
||||
|
@ -107,24 +111,7 @@ export function MarketProvider({ children = null as any }) {
|
|||
if (market) {
|
||||
const programId = market.marketInfo.programId;
|
||||
const id = market.marketInfo.address;
|
||||
cache.add(id, item, (id, acc) => {
|
||||
const decoded = Market.getLayout(programId).decode(acc.data);
|
||||
|
||||
const details = {
|
||||
pubkey: id,
|
||||
account: {
|
||||
...acc,
|
||||
},
|
||||
info: decoded,
|
||||
} as ParsedAccountBase;
|
||||
|
||||
cache.registerParser(details.info.baseMint, MintParser);
|
||||
cache.registerParser(details.info.quoteMint, MintParser);
|
||||
cache.registerParser(details.info.bids, OrderBookParser);
|
||||
cache.registerParser(details.info.asks, OrderBookParser);
|
||||
|
||||
return details;
|
||||
});
|
||||
cache.add(id, item, DexMarketParser);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,19 +243,7 @@ export const useMidPriceInUSD = (mint: string) => {
|
|||
return { price, isBase: price === 1.0 };
|
||||
};
|
||||
|
||||
const OrderBookParser = (id: PublicKey, acc: AccountInfo<Buffer>) => {
|
||||
const decoded = Orderbook.LAYOUT.decode(acc.data);
|
||||
|
||||
const details = {
|
||||
pubkey: id,
|
||||
account: {
|
||||
...acc,
|
||||
},
|
||||
info: decoded,
|
||||
} as ParsedAccountBase;
|
||||
|
||||
return details;
|
||||
};
|
||||
|
||||
const getMidPrice = (marketAddress?: string, mintAddress?: string) => {
|
||||
const SERUM_TOKEN = TOKEN_MINTS.find(
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { useContext } from "react";
|
||||
import { TokenAccount } from "../models";
|
||||
import { useAccountsContext } from './../contexts/accounts';
|
||||
|
||||
|
|
|
@ -11,12 +11,12 @@ export function useUserBalance(mint?: PublicKey) {
|
|||
return userAccounts
|
||||
.filter(acc => mint?.equals(acc.info.mint))
|
||||
.sort((a, b) => b.info.amount.sub(a.info.amount).toNumber());
|
||||
}, [userAccounts]);
|
||||
}, [userAccounts, mint]);
|
||||
|
||||
const balanceLamports = useMemo(() => {
|
||||
return accounts
|
||||
.reduce((res, item) => res += item.info.amount.toNumber(), 0);
|
||||
},[accounts, mintInfo]);
|
||||
},[accounts]);
|
||||
|
||||
return {
|
||||
balance: fromLamports(balanceLamports, mintInfo),
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from "./market";
|
|
@ -0,0 +1,44 @@
|
|||
import { Market, MARKETS, Orderbook } from "@project-serum/serum";
|
||||
import { AccountInfo, PublicKey } from "@solana/web3.js";
|
||||
import {
|
||||
MintParser,
|
||||
ParsedAccountBase,
|
||||
cache,
|
||||
} from "./../../contexts/accounts";
|
||||
|
||||
export const OrderBookParser = (id: PublicKey, acc: AccountInfo<Buffer>) => {
|
||||
const decoded = Orderbook.LAYOUT.decode(acc.data);
|
||||
|
||||
const details = {
|
||||
pubkey: id,
|
||||
account: {
|
||||
...acc,
|
||||
},
|
||||
info: decoded,
|
||||
} as ParsedAccountBase;
|
||||
|
||||
return details;
|
||||
};
|
||||
|
||||
const DEFAULT_DEX_ID = new PublicKey('EUqojwWA2rd19FZrzeBncJsm38Jm1hEhE3zsmX3bRc2o');
|
||||
|
||||
export const DexMarketParser = (pubkey: PublicKey, acc: AccountInfo<Buffer>) => {
|
||||
const market = MARKETS.find(m => m.address.equals(pubkey));
|
||||
const decoded = Market.getLayout(market?.programId || DEFAULT_DEX_ID)
|
||||
.decode(acc.data);
|
||||
|
||||
const details = {
|
||||
pubkey,
|
||||
account: {
|
||||
...acc,
|
||||
},
|
||||
info: decoded,
|
||||
} as ParsedAccountBase;
|
||||
|
||||
cache.registerParser(details.info.baseMint, MintParser);
|
||||
cache.registerParser(details.info.quoteMint, MintParser);
|
||||
cache.registerParser(details.info.bids, OrderBookParser);
|
||||
cache.registerParser(details.info.asks, OrderBookParser);
|
||||
|
||||
return details;
|
||||
}
|
|
@ -48,12 +48,15 @@ export const borrowInstruction = (
|
|||
|
||||
dexMarket: PublicKey,
|
||||
dexOrderBookSide: PublicKey,
|
||||
|
||||
memory: PublicKey,
|
||||
): TransactionInstruction => {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u8("instruction"),
|
||||
Layout.uint64("collateralAmount"),
|
||||
]);
|
||||
|
||||
debugger;
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
|
@ -77,6 +80,7 @@ export const borrowInstruction = (
|
|||
{ pubkey: lendingMarketAuthority, isSigner: false, isWritable: true },
|
||||
{ pubkey: dexMarket, isSigner: false, isWritable: true },
|
||||
{ pubkey: dexOrderBookSide, isSigner: false, isWritable: false },
|
||||
{ pubkey: memory, isSigner: false, isWritable: true },
|
||||
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
|
||||
{ pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
|
||||
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
||||
|
|
|
@ -16,6 +16,7 @@ export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.
|
|||
Layout.uint64("lastUpdateSlot"),
|
||||
Layout.publicKey("lendingMarket"),
|
||||
Layout.publicKey("liquidityMint"),
|
||||
BufferLayout.u8("liquidityMintDecimals"),
|
||||
Layout.publicKey("liquiditySupply"),
|
||||
Layout.publicKey("collateralMint"),
|
||||
Layout.publicKey("collateralSupply"),
|
||||
|
@ -23,9 +24,16 @@ export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.
|
|||
BufferLayout.u32('dexMarketOption'),
|
||||
Layout.publicKey("dexMarket"),
|
||||
|
||||
BufferLayout.struct([
|
||||
/// Max utilization rate as a percent
|
||||
BufferLayout.u8("maxUtilizationRate"),
|
||||
|
||||
BufferLayout.u8("collateralFactor"),
|
||||
/// The ratio of the loan to the value of the collateral as a percent
|
||||
BufferLayout.u8("loanToValueRatio"),
|
||||
/// The percent discount the liquidator gets when buying collateral for an unhealthy obligation
|
||||
BufferLayout.u8("liquidationBonus"),
|
||||
/// The percent at which an obligation is considered unhealthy
|
||||
BufferLayout.u8("liquidationThreshold"),
|
||||
], "config"),
|
||||
|
||||
Layout.uint128("cumulativeBorrowRate"),
|
||||
Layout.uint128("totalBorrows"),
|
||||
|
@ -36,6 +44,8 @@ export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.
|
|||
);
|
||||
|
||||
export const isLendingReserve = (info: AccountInfo<Buffer>) => {
|
||||
console.log(LendingReserveLayout.span);
|
||||
console.log(info.data.length);
|
||||
return info.data.length === LendingReserveLayout.span;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue