refactoring

This commit is contained in:
jordansexton 2021-05-06 12:41:07 -05:00
parent 97bc5f76e3
commit cee89c00d3
16 changed files with 553 additions and 197 deletions

View File

@ -34,7 +34,7 @@ export const borrowObligationLiquidity = async (
obligation: ParsedAccount<Obligation>, obligation: ParsedAccount<Obligation>,
) => { ) => {
notify({ notify({
message: 'Borrowing funds...', message: 'Borrowing liquidity...',
description: 'Please review transactions to approve.', description: 'Please review transactions to approve.',
type: 'warn', type: 'warn',
}); });
@ -146,7 +146,7 @@ export const borrowObligationLiquidity = async (
); );
notify({ notify({
message: 'Funds borrowed.', message: 'Liquidity borrowed.',
type: 'success', type: 'success',
description: `Transaction - ${txid}`, description: `Transaction - ${txid}`,
}); });

View File

@ -0,0 +1,100 @@
import {
contexts,
LENDING_PROGRAM_ID,
models,
notify,
TokenAccount,
} from '@oyster/common';
import {
Account,
Connection,
PublicKey,
TransactionInstruction,
} from '@solana/web3.js';
import {
depositObligationCollateralInstruction,
refreshReserveInstruction,
Reserve,
} from '../models';
const { approve } = models;
const { sendTransaction } = contexts.Connection;
// @FIXME
export const depositObligationCollateral = async (
connection: Connection,
wallet: any,
collateralAmount: number,
source: TokenAccount,
reserve: Reserve,
reserveAddress: PublicKey,
obligationAddress: PublicKey
) => {
notify({
message: 'Depositing collateral...',
description: 'Please review transactions to approve.',
type: 'warn',
});
// user from account
const signers: Account[] = [];
const instructions: TransactionInstruction[] = [];
const cleanupInstructions: TransactionInstruction[] = [];
const [lendingMarketAuthority] = await PublicKey.findProgramAddress(
[reserve.lendingMarket.toBuffer()],
LENDING_PROGRAM_ID,
);
const sourceCollateral = source.pubkey;
// create approval for transfer transactions
const transferAuthority = approve(
instructions,
cleanupInstructions,
sourceCollateral,
wallet.publicKey,
collateralAmount,
);
signers.push(transferAuthority);
instructions.push(
refreshReserveInstruction(
reserveAddress,
reserve.liquidity.oracleOption
? reserve.liquidity.oraclePubkey
: undefined,
),
depositObligationCollateralInstruction(
collateralAmount,
sourceCollateral,
reserve.collateral.mintPubkey,
reserveAddress,
obligationAddress,
reserve.lendingMarket,
lendingMarketAuthority,
// @FIXME: wallet must sign
wallet.publicKey,
transferAuthority.publicKey,
),
);
try {
let { txid } = await sendTransaction(
connection,
wallet,
instructions.concat(cleanupInstructions),
signers,
true,
);
notify({
message: 'Collateral deposited.',
type: 'success',
description: `Transaction - ${txid}`,
});
} catch {
// TODO:
}
};

View File

@ -15,20 +15,14 @@ import {
} from '@solana/web3.js'; } from '@solana/web3.js';
import { import {
depositReserveLiquidityInstruction, depositReserveLiquidityInstruction,
initReserveInstruction,
refreshReserveInstruction, refreshReserveInstruction,
Reserve, Reserve,
} from '../models'; } from '../models';
const { sendTransaction } = contexts.Connection; const { sendTransaction } = contexts.Connection;
const { const { ensureSplAccount, findOrCreateAccountByMint } = actions;
createUninitializedAccount,
ensureSplAccount,
findOrCreateAccountByMint,
} = actions;
const { approve } = models; const { approve } = models;
// @FIXME: split up into deposit, and init which requires lending market owner
export const depositReserveLiquidity = async ( export const depositReserveLiquidity = async (
connection: Connection, connection: Connection,
wallet: any, wallet: any,
@ -38,13 +32,11 @@ export const depositReserveLiquidity = async (
reserveAddress: PublicKey, reserveAddress: PublicKey,
) => { ) => {
notify({ notify({
message: 'Depositing funds...', message: 'Depositing liquidity...',
description: 'Please review transactions to approve.', description: 'Please review transactions to approve.',
type: 'warn', type: 'warn',
}); });
const isInitalized = true; // TODO: finish reserve init
// user from account // user from account
const signers: Account[] = []; const signers: Account[] = [];
const instructions: TransactionInstruction[] = []; const instructions: TransactionInstruction[] = [];
@ -79,70 +71,35 @@ export const depositReserveLiquidity = async (
signers.push(transferAuthority); signers.push(transferAuthority);
let destinationCollateralAccount: PublicKey = isInitalized let destinationCollateralAccount: PublicKey = await findOrCreateAccountByMint(
? await findOrCreateAccountByMint( wallet.publicKey,
wallet.publicKey, wallet.publicKey,
wallet.publicKey, instructions,
instructions, cleanupInstructions,
cleanupInstructions, accountRentExempt,
accountRentExempt, reserve.collateral.mintPubkey,
reserve.collateral.mintPubkey, signers,
signers, );
)
: createUninitializedAccount(
instructions,
wallet.publicKey,
accountRentExempt,
signers,
);
if (isInitalized) { instructions.push(
instructions.push( refreshReserveInstruction(
refreshReserveInstruction( reserveAddress,
reserveAddress, reserve.liquidity.oracleOption
reserve.liquidity.oracleOption ? reserve.liquidity.oraclePubkey
? reserve.liquidity.oraclePubkey : undefined,
: undefined, ),
), depositReserveLiquidityInstruction(
depositReserveLiquidityInstruction( liquidityAmount,
liquidityAmount, sourceLiquidityAccount,
sourceLiquidityAccount, destinationCollateralAccount,
destinationCollateralAccount, reserveAddress,
reserveAddress, reserve.liquidity.supplyPubkey,
reserve.liquidity.supplyPubkey, reserve.collateral.mintPubkey,
reserve.collateral.mintPubkey, reserve.lendingMarket,
reserve.lendingMarket, lendingMarketAuthority,
lendingMarketAuthority, transferAuthority.publicKey,
transferAuthority.publicKey, ),
), );
);
} else {
// TODO: finish reserve init
// @FIXME: reserve config
const MAX_UTILIZATION_RATE = 80;
instructions.push(
initReserveInstruction(
liquidityAmount,
MAX_UTILIZATION_RATE,
sourceLiquidityAccount,
destinationCollateralAccount,
reserveAddress,
reserve.liquidity.mintPubkey,
reserve.liquidity.supplyPubkey,
reserve.liquidity.feeReceiver,
reserve.collateral.mintPubkey,
reserve.collateral.supplyPubkey,
reserve.lendingMarket,
lendingMarketAuthority,
// @FIXME: lending market owner
lendingMarketOwner,
transferAuthority.publicKey,
reserve.liquidity.oracleOption
? reserve.liquidity.oraclePubkey
: undefined,
),
);
}
try { try {
let { txid } = await sendTransaction( let { txid } = await sendTransaction(
@ -154,7 +111,7 @@ export const depositReserveLiquidity = async (
); );
notify({ notify({
message: 'Funds deposited.', message: 'Liquidity deposited.',
type: 'success', type: 'success',
description: `Transaction - ${txid}`, description: `Transaction - ${txid}`,
}); });

View File

@ -0,0 +1,59 @@
import { contexts, notify } from '@oyster/common';
import {
Account,
Connection,
PublicKey,
TransactionInstruction,
} from '@solana/web3.js';
import { initObligationInstruction, Obligation } from '../models';
const { sendTransaction } = contexts.Connection;
export const initObligation = async (
connection: Connection,
wallet: any,
obligation: Obligation,
obligationAddress: PublicKey
) => {
notify({
message: 'Initializing obligation...',
description: 'Please review transactions to approve.',
type: 'warn',
});
// user from account
const signers: Account[] = [];
const instructions: TransactionInstruction[] = [];
const cleanupInstructions: TransactionInstruction[] = [];
// @FIXME: obligation owner must sign
signers.push(wallet.info.account);
instructions.push(
initObligationInstruction(
obligationAddress,
obligation.lendingMarket,
// @FIXME: need to sign with wallet
wallet.publicKey
),
);
try {
let { txid } = await sendTransaction(
connection,
wallet,
instructions.concat(cleanupInstructions),
signers,
true,
);
notify({
message: 'Obligation initialized.',
type: 'success',
description: `Transaction - ${txid}`,
});
} catch {
// TODO:
throw new Error();
}
};

View File

@ -0,0 +1,122 @@
import {
actions,
contexts,
LENDING_PROGRAM_ID,
models,
notify,
TokenAccount,
} from '@oyster/common';
import { AccountLayout } from '@solana/spl-token';
import {
Account,
Connection,
PublicKey,
TransactionInstruction,
} from '@solana/web3.js';
import { initReserveInstruction, Reserve } from '../models';
const { sendTransaction } = contexts.Connection;
const {
createUninitializedAccount,
ensureSplAccount,
} = actions;
const { approve } = models;
export const initReserve = async (
connection: Connection,
// @FIXME: wallet must be lending market owner
wallet: any,
liquidityAmount: number,
source: TokenAccount,
reserve: Reserve,
reserveAddress: PublicKey,
) => {
notify({
message: 'Initializing reserve...',
description: 'Please review transactions to approve.',
type: 'warn',
});
// user from account
const signers: Account[] = [];
const instructions: TransactionInstruction[] = [];
const cleanupInstructions: TransactionInstruction[] = [];
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
AccountLayout.span,
);
const [lendingMarketAuthority] = await PublicKey.findProgramAddress(
[reserve.lendingMarket.toBuffer()], // which account should be authority
LENDING_PROGRAM_ID,
);
const sourceLiquidityAccount = ensureSplAccount(
instructions,
cleanupInstructions,
source,
wallet.publicKey,
liquidityAmount + accountRentExempt,
signers,
);
// create approval for transfer transactions
const transferAuthority = approve(
instructions,
cleanupInstructions,
sourceLiquidityAccount,
wallet.publicKey,
liquidityAmount,
);
signers.push(transferAuthority);
let destinationCollateralAccount: PublicKey = createUninitializedAccount(
instructions,
wallet.publicKey,
accountRentExempt,
signers,
);
instructions.push(
initReserveInstruction(
liquidityAmount,
reserve.config,
sourceLiquidityAccount,
destinationCollateralAccount,
reserveAddress,
reserve.liquidity.mintPubkey,
reserve.liquidity.supplyPubkey,
reserve.liquidity.feeReceiver,
reserve.collateral.mintPubkey,
reserve.collateral.supplyPubkey,
reserve.lendingMarket,
lendingMarketAuthority,
// @FIXME: need to sign with wallet as lending market owner
wallet.publicKey,
transferAuthority.publicKey,
reserve.liquidity.oracleOption
? reserve.liquidity.oraclePubkey
: undefined,
),
);
try {
let { txid } = await sendTransaction(
connection,
wallet,
instructions.concat(cleanupInstructions),
signers,
true,
);
notify({
message: 'Reserve initialized.',
type: 'success',
description: `Transaction - ${txid}`,
});
} catch {
// TODO:
throw new Error();
}
};

View File

@ -39,7 +39,7 @@ export const liquidateObligation = async (
obligation: ParsedAccount<Obligation>, obligation: ParsedAccount<Obligation>,
) => { ) => {
notify({ notify({
message: 'Repaying funds...', message: 'Liquidating obligation...',
description: 'Please review transactions to approve.', description: 'Please review transactions to approve.',
type: 'warn', type: 'warn',
}); });
@ -146,7 +146,7 @@ export const liquidateObligation = async (
); );
notify({ notify({
message: 'Funds liquidated.', message: 'Obligation liquidated.',
type: 'success', type: 'success',
description: `Transaction - ${txid}`, description: `Transaction - ${txid}`,
}); });

View File

@ -32,7 +32,7 @@ export const redeemReserveCollateral = async (
reserveAddress: PublicKey, reserveAddress: PublicKey,
) => { ) => {
notify({ notify({
message: 'Withdrawing funds...', message: 'Redeeming collateral...',
description: 'Please review transactions to approve.', description: 'Please review transactions to approve.',
type: 'warn', type: 'warn',
}); });
@ -105,7 +105,7 @@ export const redeemReserveCollateral = async (
); );
notify({ notify({
message: 'Funds deposited.', message: 'Collateral redeemed.',
type: 'success', type: 'success',
description: `Transaction - ${txid}`, description: `Transaction - ${txid}`,
}); });

View File

@ -35,7 +35,7 @@ export const repayObligationLiquidity = async (
obligation: ParsedAccount<Obligation>, obligation: ParsedAccount<Obligation>,
) => { ) => {
notify({ notify({
message: 'Repaying funds...', message: 'Repaying liquidity...',
description: 'Please review transactions to approve.', description: 'Please review transactions to approve.',
type: 'warn', type: 'warn',
}); });
@ -117,7 +117,7 @@ export const repayObligationLiquidity = async (
); );
notify({ notify({
message: 'Funds repaid.', message: 'Liquidity repaid.',
type: 'success', type: 'success',
description: `Transaction - ${txid}`, description: `Transaction - ${txid}`,
}); });

View File

@ -0,0 +1,106 @@
import {
contexts,
findOrCreateAccountByMint,
LENDING_PROGRAM_ID,
models,
notify,
TokenAccount,
} from '@oyster/common';
import { AccountLayout } from '@solana/spl-token';
import {
Account,
Connection,
PublicKey,
TransactionInstruction,
} from '@solana/web3.js';
import {
withdrawObligationCollateralInstruction,
refreshReserveInstruction,
Reserve,
} from '../models';
const { approve } = models;
const { sendTransaction } = contexts.Connection;
// @FIXME
export const withdrawObligationCollateral = async (
connection: Connection,
wallet: any,
collateralAmount: number,
source: TokenAccount,
reserve: Reserve,
reserveAddress: PublicKey,
obligationAddress: PublicKey,
) => {
notify({
message: 'Withdrawing collateral...',
description: 'Please review transactions to approve.',
type: 'warn',
});
// user from account
const signers: Account[] = [];
const instructions: TransactionInstruction[] = [];
const cleanupInstructions: TransactionInstruction[] = [];
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
AccountLayout.span,
);
const [lendingMarketAuthority] = await PublicKey.findProgramAddress(
[reserve.lendingMarket.toBuffer()],
LENDING_PROGRAM_ID,
);
// @FIXME: wallet must sign as obligation owner
signers.push(wallet.info.account);
// get destination account
const destinationCollateral = await findOrCreateAccountByMint(
wallet.publicKey,
wallet.publicKey,
instructions,
cleanupInstructions,
accountRentExempt,
reserve.collateral.mintPubkey,
signers,
);
instructions.push(
refreshReserveInstruction(
reserveAddress,
reserve.liquidity.oracleOption
? reserve.liquidity.oraclePubkey
: undefined,
),
withdrawObligationCollateralInstruction(
collateralAmount,
reserve.collateral.supplyPubkey,
destinationCollateral,
reserveAddress,
obligationAddress,
reserve.lendingMarket,
lendingMarketAuthority,
// @FIXME: wallet must sign
wallet.publicKey
),
);
try {
let { txid } = await sendTransaction(
connection,
wallet,
instructions.concat(cleanupInstructions),
signers,
true,
);
notify({
message: 'Collateral withdrawn.',
type: 'success',
description: `Transaction - ${txid}`,
});
} catch {
// TODO:
}
};

View File

@ -145,9 +145,7 @@ export const BorrowInput = (props: {
parseFloat(value), parseFloat(value),
borrowReserve, borrowReserve,
// TODO: select existing obligations by collateral reserve // TODO: select existing obligations by collateral reserve
userObligationsByReserve.length > 0 userObligationsByReserve[0].obligation.account
? userObligationsByReserve[0].obligation.account
: undefined,
); );
setValue(''); setValue('');

View File

@ -45,13 +45,11 @@ export const useLending = () => {
const processAccount = useCallback( const processAccount = useCallback(
(item: { pubkey: PublicKey; account: AccountInfo<Buffer> }) => { (item: { pubkey: PublicKey; account: AccountInfo<Buffer> }) => {
if (isReserve(item.account)) { if (isReserve(item.account)) {
const reserve = cache.add( return cache.add(
item.pubkey.toBase58(), item.pubkey.toBase58(),
item.account, item.account,
ReserveParser, ReserveParser,
); );
return reserve;
} else if (isLendingMarket(item.account)) { } else if (isLendingMarket(item.account)) {
return cache.add( return cache.add(
item.pubkey.toBase58(), item.pubkey.toBase58(),

View File

@ -8,6 +8,7 @@ import {
import BN from 'bn.js'; import BN from 'bn.js';
import * as BufferLayout from 'buffer-layout'; import * as BufferLayout from 'buffer-layout';
import * as Layout from '../../utils/layout'; import * as Layout from '../../utils/layout';
import { ReserveConfig } from '../state';
import { LendingInstruction } from './instruction'; import { LendingInstruction } from './instruction';
/// Initializes a new lending market reserve. /// Initializes a new lending market reserve.
@ -42,8 +43,7 @@ import { LendingInstruction } from './instruction';
// }, // },
export const initReserveInstruction = ( export const initReserveInstruction = (
liquidityAmount: number | BN, liquidityAmount: number | BN,
// @FIXME: reserve config config: ReserveConfig,
maxUtilizationRate: number,
sourceLiquidity: PublicKey, sourceLiquidity: PublicKey,
destinationCollateral: PublicKey, destinationCollateral: PublicKey,
reserve: PublicKey, reserve: PublicKey,
@ -61,8 +61,15 @@ export const initReserveInstruction = (
const dataLayout = BufferLayout.struct([ const dataLayout = BufferLayout.struct([
BufferLayout.u8('instruction'), BufferLayout.u8('instruction'),
Layout.uint64('liquidityAmount'), Layout.uint64('liquidityAmount'),
// @FIXME: reserve config BufferLayout.u8('optimalUtilizationRate'),
BufferLayout.u8('maxUtilizationRate'), BufferLayout.u8('loanToValueRatio'),
BufferLayout.u8('liquidationBonus'),
BufferLayout.u8('liquidationThreshold'),
BufferLayout.u8('minBorrowRate'),
BufferLayout.u8('optimalBorrowRate'),
BufferLayout.u8('maxBorrowRate'),
Layout.uint64('borrowFeeWad'),
BufferLayout.u8('hostFeePercentage'),
]); ]);
const data = Buffer.alloc(dataLayout.span); const data = Buffer.alloc(dataLayout.span);
@ -70,7 +77,15 @@ export const initReserveInstruction = (
{ {
instruction: LendingInstruction.InitReserve, instruction: LendingInstruction.InitReserve,
liquidityAmount: new BN(liquidityAmount), liquidityAmount: new BN(liquidityAmount),
maxUtilizationRate, optimalUtilizationRate: config.optimalUtilizationRate,
loanToValueRatio: config.loanToValueRatio,
liquidationBonus: config.liquidationBonus,
liquidationThreshold: config.liquidationThreshold,
minBorrowRate: config.minBorrowRate,
optimalBorrowRate: config.optimalBorrowRate,
maxBorrowRate: config.maxBorrowRate,
borrowFeeWad: config.fees.borrowFeeWad,
hostFeePercentage: config.fees.hostFeePercentage,
}, },
data, data,
); );

View File

@ -1,4 +1,11 @@
import BN from 'bn.js'; import BN from 'bn.js';
import * as BufferLayout from 'buffer-layout';
import * as Layout from '../../utils/layout';
export const LastUpdateLayout: typeof BufferLayout.Structure = BufferLayout.struct(
[Layout.uint64('slot'), BufferLayout.u8('stale')],
'lastUpdate'
);
export interface LastUpdate { export interface LastUpdate {
slot: BN; slot: BN;

View File

@ -2,6 +2,13 @@ import { AccountInfo, PublicKey } from '@solana/web3.js';
import * as BufferLayout from 'buffer-layout'; import * as BufferLayout from 'buffer-layout';
import * as Layout from '../../utils/layout'; import * as Layout from '../../utils/layout';
export interface LendingMarket {
version: number;
isInitialized: boolean;
quoteTokenMint: PublicKey;
tokenProgramId: PublicKey;
}
export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.struct( export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.struct(
[ [
BufferLayout.u8('version'), BufferLayout.u8('version'),
@ -14,13 +21,6 @@ export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.s
], ],
); );
export interface LendingMarket {
version: number;
isInitialized: boolean;
quoteTokenMint: PublicKey;
tokenProgramId: PublicKey;
}
export const isLendingMarket = (info: AccountInfo<Buffer>) => { export const isLendingMarket = (info: AccountInfo<Buffer>) => {
return info.data.length === LendingMarketLayout.span; return info.data.length === LendingMarketLayout.span;
}; };

View File

@ -2,16 +2,41 @@ import { AccountInfo, PublicKey } 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 * as Layout from '../../utils/layout'; import * as Layout from '../../utils/layout';
import { LastUpdate } from './lastUpdate'; import { LastUpdate, LastUpdateLayout } from './lastUpdate';
export interface Obligation {
version: number;
lastUpdate: LastUpdate;
lendingMarket: PublicKey;
owner: PublicKey;
// @FIXME: check usages
deposits: ObligationCollateral[];
// @FIXME: check usages
borrows: ObligationLiquidity[];
depositedValue: BN; // decimals
borrowedValue: BN; // decimals
allowedBorrowValue: BN; // decimals
unhealthyBorrowValue: BN; // decimals
}
export interface ObligationCollateral {
depositReserve: PublicKey;
depositedAmount: BN;
marketValue: BN; // decimals
}
export interface ObligationLiquidity {
borrowReserve: PublicKey;
cumulativeBorrowRateWads: BN; // decimals
borrowedAmountWads: BN; // decimals
marketValue: BN; // decimals
}
export const ObligationLayout: typeof BufferLayout.Structure = BufferLayout.struct( export const ObligationLayout: typeof BufferLayout.Structure = BufferLayout.struct(
[ [
BufferLayout.u8('version'), BufferLayout.u8('version'),
BufferLayout.struct( LastUpdateLayout,
[Layout.uint64('slot'), BufferLayout.u8('stale')],
'lastUpdate',
),
Layout.publicKey('lendingMarket'), Layout.publicKey('lendingMarket'),
Layout.publicKey('owner'), Layout.publicKey('owner'),
@ -61,34 +86,6 @@ export interface ProtoObligation {
dataFlat: Buffer; dataFlat: Buffer;
} }
export interface Obligation {
version: number;
lastUpdate: LastUpdate;
lendingMarket: PublicKey;
owner: PublicKey;
// @FIXME: check usages
deposits: ObligationCollateral[];
// @FIXME: check usages
borrows: ObligationLiquidity[];
depositedValue: BN; // decimals
borrowedValue: BN; // decimals
allowedBorrowValue: BN; // decimals
unhealthyBorrowValue: BN; // decimals
}
export interface ObligationCollateral {
depositReserve: PublicKey;
depositedAmount: BN;
marketValue: BN; // decimals
}
export interface ObligationLiquidity {
borrowReserve: PublicKey;
cumulativeBorrowRateWads: BN; // decimals
borrowedAmountWads: BN; // decimals
marketValue: BN; // decimals
}
export const ObligationParser = ( export const ObligationParser = (
pubkey: PublicKey, pubkey: PublicKey,
info: AccountInfo<Buffer>, info: AccountInfo<Buffer>,

View File

@ -3,70 +3,7 @@ import { AccountInfo, PublicKey } 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 * as Layout from '../../utils/layout'; import * as Layout from '../../utils/layout';
import { LastUpdate } from './lastUpdate'; import { LastUpdate, LastUpdateLayout } from './lastUpdate';
export const ReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct(
[
BufferLayout.u8('version'),
BufferLayout.struct(
[Layout.uint64('slot'), BufferLayout.u8('stale')],
'lastUpdate',
),
Layout.publicKey('lendingMarket'),
BufferLayout.struct(
[
Layout.publicKey('mintPubkey'),
BufferLayout.u8('mintDecimals'),
Layout.publicKey('supplyPubkey'),
Layout.publicKey('feeReceiver'),
// @FIXME: oracle option
// TODO: replace u32 option with generic equivalent
BufferLayout.u32('oracleOption'),
Layout.publicKey('oracle'),
Layout.uint64('availableAmount'),
Layout.uint128('borrowedAmountWads'),
Layout.uint128('cumulativeBorrowRateWads'),
Layout.uint64('marketPrice'),
],
'liquidity',
),
BufferLayout.struct(
[
Layout.publicKey('mintPubkey'),
Layout.uint64('mintTotalSupply'),
Layout.publicKey('supplyPubkey'),
],
'collateral',
),
BufferLayout.struct(
[
BufferLayout.u8('optimalUtilizationRate'),
BufferLayout.u8('loanToValueRatio'),
BufferLayout.u8('liquidationBonus'),
BufferLayout.u8('liquidationThreshold'),
BufferLayout.u8('minBorrowRate'),
BufferLayout.u8('optimalBorrowRate'),
BufferLayout.u8('maxBorrowRate'),
BufferLayout.struct(
[Layout.uint64('borrowFeeWad'), BufferLayout.u8('hostFeePercentage')],
'fees',
),
],
'config',
),
BufferLayout.blob(256, 'padding'),
],
);
export const isReserve = (info: AccountInfo<Buffer>) => {
return info.data.length === ReserveLayout.span;
};
export interface Reserve { export interface Reserve {
version: number; version: number;
@ -111,6 +48,66 @@ export interface ReserveConfig {
}; };
} }
export const ReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct(
[
BufferLayout.u8('version'),
LastUpdateLayout,
Layout.publicKey('lendingMarket'),
BufferLayout.struct(
[
Layout.publicKey('mintPubkey'),
BufferLayout.u8('mintDecimals'),
Layout.publicKey('supplyPubkey'),
Layout.publicKey('feeReceiver'),
// @FIXME: oracle option
// TODO: replace u32 option with generic equivalent
BufferLayout.u32('oracleOption'),
Layout.publicKey('oracle'),
Layout.uint64('availableAmount'),
Layout.uint128('borrowedAmountWads'),
Layout.uint128('cumulativeBorrowRateWads'),
Layout.uint64('marketPrice'),
],
'liquidity',
),
BufferLayout.struct(
[
Layout.publicKey('mintPubkey'),
Layout.uint64('mintTotalSupply'),
Layout.publicKey('supplyPubkey'),
],
'collateral'
),
BufferLayout.struct(
[
BufferLayout.u8('optimalUtilizationRate'),
BufferLayout.u8('loanToValueRatio'),
BufferLayout.u8('liquidationBonus'),
BufferLayout.u8('liquidationThreshold'),
BufferLayout.u8('minBorrowRate'),
BufferLayout.u8('optimalBorrowRate'),
BufferLayout.u8('maxBorrowRate'),
BufferLayout.struct(
[Layout.uint64('borrowFeeWad'), BufferLayout.u8('hostFeePercentage')],
'fees',
),
],
'config'
),
BufferLayout.blob(256, 'padding'),
],
);
export const isReserve = (info: AccountInfo<Buffer>) => {
return info.data.length === ReserveLayout.span;
};
export const ReserveParser = (pubkey: PublicKey, info: AccountInfo<Buffer>) => { export const ReserveParser = (pubkey: PublicKey, info: AccountInfo<Buffer>) => {
const buffer = Buffer.from(info.data); const buffer = Buffer.from(info.data);
const reserve = ReserveLayout.decode(buffer) as Reserve; const reserve = ReserveLayout.decode(buffer) as Reserve;