${formatNumber.format(collateralBalanceInUSD)}
diff --git a/packages/lending/src/components/WithdrawInput/index.tsx b/packages/lending/src/components/WithdrawInput/index.tsx
index 29f6bb2b..54e5f904 100644
--- a/packages/lending/src/components/WithdrawInput/index.tsx
+++ b/packages/lending/src/components/WithdrawInput/index.tsx
@@ -1,24 +1,25 @@
+import { ActionConfirmation, ConnectButton, contexts } from '@oyster/common';
+import { PublicKey } from '@solana/web3.js';
+import { Card, Slider } from 'antd';
import React, { useCallback, useState } from 'react';
+import { redeemReserveCollateral } from '../../actions';
+import { LABELS, marks } from '../../constants';
import {
InputType,
- useUserCollateralBalance,
useSliderInput,
useUserBalance,
+ useUserCollateralBalance,
} from '../../hooks';
-import { LendingReserve } from '../../models/lending';
-import { Card, Slider } from 'antd';
-import { withdraw } from '../../actions';
-import { PublicKey } from '@solana/web3.js';
-import './style.less';
-import { LABELS, marks } from '../../constants';
+import { Reserve } from '../../models';
import CollateralInput from '../CollateralInput';
-import { contexts, ConnectButton, ActionConfirmation } from '@oyster/common';
+import './style.less';
+
const { useConnection } = contexts.Connection;
const { useWallet } = contexts.Wallet;
export const WithdrawInput = (props: {
className?: string;
- reserve: LendingReserve;
+ reserve: Reserve;
address: PublicKey;
}) => {
const connection = useConnection();
@@ -32,7 +33,7 @@ export const WithdrawInput = (props: {
const {
balanceLamports: collateralBalanceLamports,
accounts: fromAccounts,
- } = useUserBalance(reserve?.collateralMint);
+ } = useUserBalance(reserve?.collateral.mint);
const { balance: collateralBalanceInLiquidity } = useUserCollateralBalance(
reserve,
);
@@ -64,7 +65,7 @@ export const WithdrawInput = (props: {
),
collateralBalanceLamports,
);
- await withdraw(
+ await redeemReserveCollateral(
fromAccounts[0],
withdrawAmount,
reserve,
diff --git a/packages/lending/src/contexts/lending.tsx b/packages/lending/src/contexts/lending.tsx
index 665f080d..b70976e1 100644
--- a/packages/lending/src/contexts/lending.tsx
+++ b/packages/lending/src/contexts/lending.tsx
@@ -1,22 +1,20 @@
+import { contexts, LENDING_PROGRAM_ID, ParsedAccount } from '@oyster/common';
+import { AccountInfo, PublicKey } from '@solana/web3.js';
import React, { useCallback, useEffect, useState } from 'react';
-
+import { useLendingReserves } from '../hooks';
import {
- LendingMarketParser,
- isLendingReserve,
isLendingMarket,
- LendingReserveParser,
- LendingReserve,
- isLendingObligation,
- LendingObligationParser,
-} from './../models/lending';
-
-import { PublicKey, AccountInfo } from '@solana/web3.js';
+ isObligation,
+ isReserve,
+ LendingMarketParser,
+ ObligationParser,
+ Reserve,
+ ReserveParser,
+} from '../models';
import { DexMarketParser } from '../models/dex';
import { usePrecacheMarket } from './market';
-import { useLendingReserves } from '../hooks';
-import { contexts, utils, ParsedAccount } from '@oyster/common';
+
const { useConnection } = contexts.Connection;
-const { LENDING_PROGRAM_ID } = utils;
const { cache, getMultipleAccounts, MintParser } = contexts.Accounts;
export interface LendingContextState {}
@@ -46,11 +44,11 @@ export const useLending = () => {
const processAccount = useCallback(
(item: { pubkey: PublicKey; account: AccountInfo
}) => {
- if (isLendingReserve(item.account)) {
+ if (isReserve(item.account)) {
const reserve = cache.add(
item.pubkey.toBase58(),
item.account,
- LendingReserveParser,
+ ReserveParser,
);
return reserve;
@@ -60,11 +58,11 @@ export const useLending = () => {
item.account,
LendingMarketParser,
);
- } else if (isLendingObligation(item.account)) {
+ } else if (isObligation(item.account)) {
return cache.add(
item.pubkey.toBase58(),
item.account,
- LendingObligationParser,
+ ObligationParser,
);
}
},
@@ -74,7 +72,7 @@ export const useLending = () => {
useEffect(() => {
if (reserveAccounts.length > 0) {
precacheMarkets(
- reserveAccounts.map(reserve => reserve.info.liquidityMint.toBase58()),
+ reserveAccounts.map(reserve => reserve.info.liquidity.mint.toBase58()),
);
}
}, [reserveAccounts, precacheMarkets]);
@@ -94,24 +92,24 @@ export const useLending = () => {
const lendingReserves = accounts
.filter(
- acc => (acc?.info as LendingReserve).lendingMarket !== undefined,
+ acc => (acc?.info as Reserve).lendingMarket !== undefined,
)
- .map(acc => acc as ParsedAccount);
+ .map(acc => acc as ParsedAccount);
const toQuery = [
...lendingReserves.map(acc => {
const result = [
cache.registerParser(
- acc?.info.collateralMint.toBase58(),
+ acc?.info.collateral.mint.toBase58(),
MintParser,
),
cache.registerParser(
- acc?.info.liquidityMint.toBase58(),
+ acc?.info.liquidity.mint.toBase58(),
MintParser,
),
// ignore dex if its not set
cache.registerParser(
- acc?.info.dexMarketOption ? acc?.info.dexMarket.toBase58() : '',
+ acc?.info.liquidity.aggregatorOption ? acc?.info.liquidity.aggregator.toBase58() : '',
DexMarketParser,
),
].filter(_ => _);
diff --git a/packages/lending/src/contexts/market.tsx b/packages/lending/src/contexts/market.tsx
index dfc83508..827a7fcd 100644
--- a/packages/lending/src/contexts/market.tsx
+++ b/packages/lending/src/contexts/market.tsx
@@ -1,26 +1,30 @@
-import React, { useCallback, useContext, useEffect, useState } from 'react';
-import { MINT_TO_MARKET } from './../models/marketOverrides';
-import { POOLS_WITH_AIRDROP } from './../models/airdrops';
-
-import { getPoolName } from '../utils/utils';
-
-import { Market, MARKETS, Orderbook, TOKEN_MINTS } from '@project-serum/serum';
-import { AccountInfo, Connection, PublicKey } from '@solana/web3.js';
-import { useMemo } from 'react';
-
import {
contexts,
- utils,
- ParsedAccount,
- KnownTokenMap,
+ convert,
EventEmitter,
+ fromLamports,
+ getTokenName,
+ KnownTokenMap,
+ ParsedAccount,
+ STABLE_COINS,
} from '@oyster/common';
-
-import { DexMarketParser } from './../models/dex';
-import { LendingMarket, LendingReserve, PoolInfo } from '../models';
+import { Market, MARKETS, Orderbook, TOKEN_MINTS } from '@project-serum/serum';
+import { AccountInfo, Connection, PublicKey } from '@solana/web3.js';
+import React, {
+ useCallback,
+ useContext,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
+import { LendingMarket, PoolInfo, Reserve } from '../models';
import { LIQUIDITY_PROVIDER_FEE, SERUM_FEE } from '../utils/pools';
+import { getPoolName } from '../utils/utils';
+import { POOLS_WITH_AIRDROP } from './../models/airdrops';
+import { DexMarketParser } from './../models/dex';
+import { MINT_TO_MARKET } from './../models/marketOverrides';
+
const { useConnectionConfig } = contexts.Connection;
-const { convert, fromLamports, getTokenName, STABLE_COINS } = utils;
const { cache, getMultipleAccounts } = contexts.Accounts;
const INITAL_LIQUIDITY_DATE = new Date('2020-10-27');
@@ -146,7 +150,7 @@ export function MarketProvider({ children = null as any }) {
}
if (!cache.get(decoded.info.baseMint)) {
- toQuery.add(decoded.info.quoteMint.toBase58());
+ toQuery.add(decoded.info.quoteTokenMint.toBase58());
}
toQuery.add(decoded.info.bids.toBase58());
@@ -509,12 +513,12 @@ export const usePrecacheMarket = () => {
export const simulateMarketOrderFill = (
amount: number,
- reserve: LendingReserve,
+ reserve: Reserve,
dex: PublicKey,
useBBO = false,
) => {
- const liquidityMint = cache.get(reserve.liquidityMint);
- const collateralMint = cache.get(reserve.collateralMint);
+ const liquidityMint = cache.get(reserve.liquidity.mint);
+ const collateralMint = cache.get(reserve.collateral.mint);
if (!liquidityMint || !collateralMint) {
return 0.0;
}
@@ -527,17 +531,17 @@ export const simulateMarketOrderFill = (
const baseMintDecimals =
cache.get(decodedMarket.baseMint)?.info.decimals || 0;
- const quoteMintDecimals =
- cache.get(decodedMarket.quoteMint)?.info.decimals || 0;
+ const quoteTokenMintDecimals =
+ cache.get(decodedMarket.quoteTokenMint)?.info.decimals || 0;
const lendingMarket = cache.get(
reserve.lendingMarket,
) as ParsedAccount;
- const dexMarket = new Market(
+ const aggregator = new Market(
decodedMarket,
baseMintDecimals,
- quoteMintDecimals,
+ quoteTokenMintDecimals,
undefined,
decodedMarket.programId,
);
@@ -548,10 +552,10 @@ export const simulateMarketOrderFill = (
return 0;
}
- const bids = new Orderbook(dexMarket, bidInfo.accountFlags, bidInfo.slab);
- const asks = new Orderbook(dexMarket, askInfo.accountFlags, askInfo.slab);
+ const bids = new Orderbook(aggregator, bidInfo.accountFlags, bidInfo.slab);
+ const asks = new Orderbook(aggregator, askInfo.accountFlags, askInfo.slab);
- const book = lendingMarket.info.quoteMint.equals(reserve.liquidityMint)
+ const book = lendingMarket.info.quoteTokenMint.equals(reserve.liquidity.mint)
? bids
: asks;
@@ -617,13 +621,13 @@ const getMidPrice = (marketAddress?: string, mintAddress?: string) => {
const baseMintDecimals =
cache.get(decodedMarket.baseMint)?.info.decimals || 0;
- const quoteMintDecimals =
- cache.get(decodedMarket.quoteMint)?.info.decimals || 0;
+ const quoteTokenMintDecimals =
+ cache.get(decodedMarket.quoteTokenMint)?.info.decimals || 0;
const market = new Market(
decodedMarket,
baseMintDecimals,
- quoteMintDecimals,
+ quoteTokenMintDecimals,
undefined,
decodedMarket.programId,
);
diff --git a/packages/lending/src/hooks/useBorrowedAmount.ts b/packages/lending/src/hooks/useBorrowedAmount.ts
index b9a71a6c..699ba1f2 100644
--- a/packages/lending/src/hooks/useBorrowedAmount.ts
+++ b/packages/lending/src/hooks/useBorrowedAmount.ts
@@ -1,13 +1,11 @@
-import { useEffect, useState } from 'react';
+import { contexts, fromLamports, wadToLamports } from '@oyster/common';
import { PublicKey } from '@solana/web3.js';
+import { useEffect, useState } from 'react';
+import { useLendingReserve } from './useLendingReserves';
import { useUserObligationByReserve } from './useUserObligationByReserve';
-import { MintInfo } from '@solana/spl-token';
-import { useLendingReserve } from './useLendingReserves';
-import { contexts, utils, ParsedAccount } from '@oyster/common';
const { cache, getMultipleAccounts, MintParser, useMint } = contexts.Accounts;
const { useConnection } = contexts.Connection;
-const { fromLamports, wadToLamports } = utils;
export function useBorrowedAmount(address?: string | PublicKey) {
const connection = useConnection();
@@ -20,7 +18,7 @@ export function useBorrowedAmount(address?: string | PublicKey) {
health: 0,
});
const reserve = useLendingReserve(address);
- const liquidityMint = useMint(reserve?.info.liquidityMint);
+ const liquidityMint = useMint(reserve?.info.liquidity.mint);
useEffect(() => {
setBorrowedInfo({
@@ -35,6 +33,7 @@ export function useBorrowedAmount(address?: string | PublicKey) {
// precache obligation mints
const { keys, array } = await getMultipleAccounts(
connection,
+ // @FIXME: obligation tokens
userObligationsByReserve.map(item =>
item.obligation.info.tokenMint.toBase58(),
),
@@ -58,17 +57,15 @@ export function useBorrowedAmount(address?: string | PublicKey) {
userObligationsByReserve.forEach(item => {
const borrowed = wadToLamports(
- item.obligation.info.borrowAmountWad,
+ item.obligation.info.borrows.borrowedAmountWads,
).toNumber();
const owned = item.userAccounts.reduce(
(amount, acc) => (amount += acc.info.amount.toNumber()),
0,
);
- const obligationMint = cache.get(
- item.obligation.info.tokenMint,
- ) as ParsedAccount;
+ // @FIXME: obligation tokens
result.borrowedLamports +=
borrowed * (owned / obligationMint?.info.supply.toNumber());
result.borrowedInUSD += item.obligation.info.borrowedInQuote;
diff --git a/packages/lending/src/hooks/useBorrowingPower.ts b/packages/lending/src/hooks/useBorrowingPower.ts
index 72c79f23..60c9f063 100644
--- a/packages/lending/src/hooks/useBorrowingPower.ts
+++ b/packages/lending/src/hooks/useBorrowingPower.ts
@@ -23,24 +23,24 @@ export function useBorrowingPower(
const reserve = useLendingReserve(key);
- const liquidityMint = reserve?.info.liquidityMint;
+ const liquidityMint = reserve?.info.liquidity.mint;
const liquidityMintAddress = liquidityMint?.toBase58();
const market = useLendingMarket(reserve?.info.lendingMarket);
- const quoteMintAddess = market?.info?.quoteMint?.toBase58();
+ const quoteTokenMintAddess = market?.info?.quoteTokenMint?.toBase58();
// TODO: remove once cross-collateral is supported
- const onlyQuoteAllowed = liquidityMintAddress !== quoteMintAddess;
+ const onlyQuoteAllowed = liquidityMintAddress !== quoteTokenMintAddess;
const exclude = useMemo(() => new Set([key]), [key]);
const inlcude = useMemo(() => {
const quoteReserve = getLendingReserves().find(
- r => r.info.liquidityMint.toBase58() === quoteMintAddess,
+ r => r.info.liquidity.mint.toBase58() === quoteTokenMintAddess,
);
return onlyQuoteAllowed && quoteReserve
? new Set([quoteReserve.pubkey.toBase58()])
: undefined;
- }, [onlyQuoteAllowed, quoteMintAddess]);
+ }, [onlyQuoteAllowed, quoteTokenMintAddess]);
const { totalInQuote } = useUserDeposits(exclude, inlcude);
@@ -53,7 +53,7 @@ export function useBorrowingPower(
const utilization = totalDeposits === 0 ? 0 : loansValue / totalDeposits;
// amounts already expressed as quite mint
- if (liquidityMintAddress === quoteMintAddess) {
+ if (liquidityMintAddress === quoteTokenMintAddess) {
return {
borrowingPower: totalInQuote,
totalInQuote,
diff --git a/packages/lending/src/hooks/useCollateralBalance.ts b/packages/lending/src/hooks/useCollateralBalance.ts
index e616b482..72955f6e 100644
--- a/packages/lending/src/hooks/useCollateralBalance.ts
+++ b/packages/lending/src/hooks/useCollateralBalance.ts
@@ -1,20 +1,19 @@
+import { contexts, fromLamports } from '@oyster/common';
import { PublicKey } from '@solana/web3.js';
import { useEffect, useMemo, useState } from 'react';
import { useMarkets } from '../contexts/market';
-import { LendingReserve, reserveMarketCap } from '../models/lending';
+import { Reserve, reserveMarketCap } from '../models';
import { useUserBalance } from './useUserBalance';
-import { contexts, utils } from '@oyster/common';
const { useMint } = contexts.Accounts;
-const { fromLamports } = utils;
export function useUserCollateralBalance(
- reserve?: LendingReserve,
+ reserve?: Reserve,
account?: PublicKey,
) {
- const mint = useMint(reserve?.collateralMint);
+ const mint = useMint(reserve?.collateral.mint);
const { balanceLamports: userBalance, accounts } = useUserBalance(
- reserve?.collateralMint,
+ reserve?.collateral.mint,
account,
);
@@ -34,12 +33,12 @@ export function useUserCollateralBalance(
useEffect(() => {
const updateBalance = () => {
setBalanceInUSD(
- balance * midPriceInUSD(reserve?.liquidityMint?.toBase58() || ''),
+ balance * midPriceInUSD(reserve?.liquidity.mint?.toBase58() || ''),
);
};
const dispose = marketEmitter.onMarket(args => {
- if (args.ids.has(reserve?.dexMarket.toBase58() || '')) {
+ if (args.ids.has(reserve?.liquidity.aggregator.toBase58() || '')) {
updateBalance();
}
});
@@ -55,17 +54,17 @@ export function useUserCollateralBalance(
balance,
balanceLamports,
balanceInUSD,
- mint: reserve?.collateralMint,
+ mint: reserve?.collateral.mint,
accounts,
hasBalance: accounts.length > 0 && balance > 0,
};
}
export function calculateCollateralBalance(
- reserve: LendingReserve,
+ reserve: Reserve,
balanceLamports: number,
) {
return (
reserveMarketCap(reserve) *
- (balanceLamports / (reserve?.state.collateralMintSupply.toNumber() || 1))
+ (balanceLamports / (reserve?.collateral.mintAmount.toNumber() || 1))
);
}
diff --git a/packages/lending/src/hooks/useEnrichedLendingObligations.ts b/packages/lending/src/hooks/useEnrichedLendingObligations.ts
index 14a833de..8006a7bf 100644
--- a/packages/lending/src/hooks/useEnrichedLendingObligations.ts
+++ b/packages/lending/src/hooks/useEnrichedLendingObligations.ts
@@ -1,33 +1,34 @@
+import {
+ contexts,
+ fromLamports,
+ getTokenName,
+ ParsedAccount,
+ wadToLamports,
+} from '@oyster/common';
+import { MintInfo } from '@solana/spl-token';
import { PublicKey } from '@solana/web3.js';
import { useCallback, useEffect, useMemo, useState } from 'react';
+import { simulateMarketOrderFill, useMarkets } from '../contexts/market';
+import { collateralToLiquidity, Obligation, Reserve } from '../models';
import { useLendingObligations } from './useLendingObligations';
-import {
- collateralToLiquidity,
- LendingObligation,
- LendingReserve,
-} from '../models/lending';
import { useLendingReserves } from './useLendingReserves';
-import { MintInfo } from '@solana/spl-token';
-import { simulateMarketOrderFill, useMarkets } from '../contexts/market';
-
-import { contexts, utils, ParsedAccount } from '@oyster/common';
const { cache } = contexts.Accounts;
const { useConnectionConfig } = contexts.Connection;
-const { fromLamports, wadToLamports, getTokenName } = utils;
-interface EnrichedLendingObligationInfo extends LendingObligation {
+interface EnrichedLendingObligationInfo extends Obligation {
ltv: number;
health: number;
borrowedInQuote: number;
collateralInQuote: number;
+ // @FIXME
liquidationThreshold: number;
repayName: string;
collateralName: string;
}
export interface EnrichedLendingObligation {
- account: ParsedAccount;
+ account: ParsedAccount;
info: EnrichedLendingObligationInfo;
}
@@ -41,7 +42,7 @@ export function useEnrichedLendingObligations() {
return reserveAccounts.reduce((map, reserve) => {
map.set(reserve.pubkey.toBase58(), reserve);
return map;
- }, new Map>());
+ }, new Map>());
}, [reserveAccounts]);
const enrichedFactory = useCallback(() => {
@@ -54,25 +55,27 @@ export function useEnrichedLendingObligations() {
.map(obligation => ({
obligation,
reserve: availableReserves.get(
- obligation.info.borrowReserve.toBase58(),
- ) as ParsedAccount,
- collateralReserve: availableReserves.get(
- obligation.info.collateralReserve.toBase58(),
- ) as ParsedAccount,
+ obligation.info.borrows.borrowReserve.toBase58(),
+ ) as ParsedAccount,
+ depositReserve: availableReserves.get(
+ obligation.info.deposits.depositReserve.toBase58(),
+ ) as ParsedAccount,
}))
// use obligations with reserves available
.filter(item => item.reserve)
// use reserves with borrow amount greater than zero
.filter(
item =>
- wadToLamports(item.obligation.info.borrowAmountWad).toNumber() > 0,
+ wadToLamports(
+ item.obligation.info.borrows.borrowedAmountWads,
+ ).toNumber() > 0,
)
.map(item => {
const obligation = item.obligation;
const reserve = item.reserve.info;
- const collateralReserve = item.reserve.info;
+ const depositReserve = item.reserve.info;
const liquidityMint = cache.get(
- reserve.liquidityMint,
+ reserve.liquidity.mint,
) as ParsedAccount;
let ltv = 0;
let health = 0;
@@ -81,31 +84,31 @@ export function useEnrichedLendingObligations() {
if (liquidityMint) {
const collateralMint = cache.get(
- item.collateralReserve.info.liquidityMint,
+ item.depositReserve.info.liquidity.mint,
);
const collateral = fromLamports(
collateralToLiquidity(
- obligation.info.depositedCollateral,
+ obligation.info.deposits.depositedAmount,
item.reserve.info,
),
collateralMint?.info,
);
const borrowed = wadToLamports(
- obligation.info.borrowAmountWad,
+ obligation.info.borrows.borrowedAmountWads,
).toNumber();
const borrowedAmount = simulateMarketOrderFill(
borrowed,
item.reserve.info,
- item.reserve.info.dexMarketOption
- ? item.reserve.info.dexMarket
- : item.collateralReserve.info.dexMarket,
+ item.reserve.info.liquidity.aggregatorOption
+ ? item.reserve.info.liquidity.aggregator
+ : item.depositReserve.info.liquidity.aggregator,
true,
);
- const liquidityMintAddress = item.reserve.info.liquidityMint.toBase58();
+ const liquidityMintAddress = item.reserve.info.liquidity.mint.toBase58();
const liquidityMint = cache.get(
liquidityMintAddress,
) as ParsedAccount;
@@ -133,10 +136,10 @@ export function useEnrichedLendingObligations() {
collateralInQuote,
liquidationThreshold:
item.reserve.info.config.liquidationThreshold,
- repayName: getTokenName(tokenMap, reserve.liquidityMint),
+ repayName: getTokenName(tokenMap, reserve.liquidity.mint),
collateralName: getTokenName(
tokenMap,
- collateralReserve.liquidityMint,
+ depositReserve.liquidity.mint,
),
},
} as EnrichedLendingObligation;
diff --git a/packages/lending/src/hooks/useLendingMarket.ts b/packages/lending/src/hooks/useLendingMarket.ts
index 674a72fb..f5b33c13 100644
--- a/packages/lending/src/hooks/useLendingMarket.ts
+++ b/packages/lending/src/hooks/useLendingMarket.ts
@@ -1,7 +1,8 @@
import { contexts, ParsedAccount } from '@oyster/common';
import { PublicKey } from '@solana/web3.js';
import { useEffect, useState } from 'react';
-import { LendingMarketParser, LendingMarket } from '../models/lending';
+import { LendingMarket, LendingMarketParser } from '../models';
+
const { cache } = contexts.Accounts;
const getLendingMarkets = () => {
diff --git a/packages/lending/src/hooks/useLendingObligations.ts b/packages/lending/src/hooks/useLendingObligations.ts
index ae221b28..292dca52 100644
--- a/packages/lending/src/hooks/useLendingObligations.ts
+++ b/packages/lending/src/hooks/useLendingObligations.ts
@@ -1,14 +1,15 @@
+import { contexts, ParsedAccount } from '@oyster/common';
import { PublicKey } from '@solana/web3.js';
import { useEffect, useState } from 'react';
-import { LendingObligation, LendingObligationParser } from '../models/lending';
-import { contexts, ParsedAccount } from '@oyster/common';
+import { Obligation, ObligationParser } from '../models';
+
const { cache } = contexts.Accounts;
const getLendingObligations = () => {
return cache
- .byParser(LendingObligationParser)
+ .byParser(ObligationParser)
.map(id => cache.get(id))
- .filter(acc => acc !== undefined) as ParsedAccount[];
+ .filter(acc => acc !== undefined) as ParsedAccount[];
};
export function useLendingObligations() {
@@ -16,7 +17,7 @@ export function useLendingObligations() {
useEffect(() => {
const dispose = cache.emitter.onCache(args => {
- if (args.parser === LendingObligationParser) {
+ if (args.parser === ObligationParser) {
setObligations(getLendingObligations());
}
});
@@ -34,13 +35,13 @@ export function useLendingObligations() {
export function useLendingObligation(address?: string | PublicKey) {
const id = typeof address === 'string' ? address : address?.toBase58();
const [obligationAccount, setObligationAccount] = useState(
- cache.get(id || '') as ParsedAccount,
+ cache.get(id || '') as ParsedAccount,
);
useEffect(() => {
const dispose = cache.emitter.onCache(args => {
if (args.id === id) {
- setObligationAccount(cache.get(id) as ParsedAccount);
+ setObligationAccount(cache.get(id) as ParsedAccount);
}
});
diff --git a/packages/lending/src/hooks/useLendingReserves.ts b/packages/lending/src/hooks/useLendingReserves.ts
index 9cf9a975..4ebc01fe 100644
--- a/packages/lending/src/hooks/useLendingReserves.ts
+++ b/packages/lending/src/hooks/useLendingReserves.ts
@@ -1,29 +1,27 @@
+import { contexts, getTokenByName, ParsedAccount } from '@oyster/common';
+import { TokenInfo } from '@solana/spl-token-registry';
import { PublicKey } from '@solana/web3.js';
import { useEffect, useMemo, useState } from 'react';
-import { LendingReserve, LendingReserveParser } from '../models/lending';
-
-import { contexts, utils, ParsedAccount } from '@oyster/common';
-import { TokenInfo } from '@solana/spl-token-registry';
+import { Reserve, ReserveParser } from '../models';
const { cache } = contexts.Accounts;
const { useConnectionConfig } = contexts.Connection;
-const { getTokenByName } = utils;
export const getLendingReserves = () => {
return cache
- .byParser(LendingReserveParser)
+ .byParser(ReserveParser)
.map(id => cache.get(id))
- .filter(acc => acc !== undefined) as ParsedAccount[];
+ .filter(acc => acc !== undefined) as ParsedAccount[];
};
export function useLendingReserves() {
const [reserveAccounts, setReserveAccounts] = useState<
- ParsedAccount[]
+ ParsedAccount[]
>(getLendingReserves());
useEffect(() => {
const dispose = cache.emitter.onCache(args => {
- if (args.parser === LendingReserveParser) {
+ if (args.parser === ReserveParser) {
setReserveAccounts(getLendingReserves());
}
});
@@ -46,7 +44,7 @@ export function useLendingReserve(address?: string | PublicKey) {
const token: TokenInfo | null = getTokenByName(tokenMap, address);
if (token) {
const account = reserveAccounts.filter(
- acc => acc.info.liquidityMint.toBase58() === token.address,
+ acc => acc.info.liquidity.mint.toBase58() === token.address,
)[0];
if (account) {
addressName = account.pubkey;
@@ -59,14 +57,14 @@ export function useLendingReserve(address?: string | PublicKey) {
[addressName],
);
- const [reserveAccount, setReserveAccount] = useState<
- ParsedAccount
- >(cache.get(id || '') as ParsedAccount);
+ const [reserveAccount, setReserveAccount] = useState>(
+ cache.get(id || '') as ParsedAccount,
+ );
useEffect(() => {
const dispose = cache.emitter.onCache(args => {
if (args.id === id) {
- setReserveAccount(cache.get(id) as ParsedAccount);
+ setReserveAccount(cache.get(id) as ParsedAccount);
}
});
diff --git a/packages/lending/src/hooks/useUserBalance.ts b/packages/lending/src/hooks/useUserBalance.ts
index 84a4807e..71dcac50 100644
--- a/packages/lending/src/hooks/useUserBalance.ts
+++ b/packages/lending/src/hooks/useUserBalance.ts
@@ -1,11 +1,9 @@
+import { contexts, fromLamports, useUserAccounts } from '@oyster/common';
import { PublicKey } from '@solana/web3.js';
import { useEffect, useMemo, useState } from 'react';
import { useMarkets } from '../contexts/market';
-import { contexts, utils, hooks } from '@oyster/common';
const { useMint } = contexts.Accounts;
-const { useUserAccounts } = hooks;
-const { fromLamports } = utils;
export function useUserBalance(
mintAddress?: PublicKey | string,
diff --git a/packages/lending/src/hooks/useUserDeposits.ts b/packages/lending/src/hooks/useUserDeposits.ts
index 2c6a24ff..f85643b0 100644
--- a/packages/lending/src/hooks/useUserDeposits.ts
+++ b/packages/lending/src/hooks/useUserDeposits.ts
@@ -1,21 +1,20 @@
-import { calculateDepositAPY, LendingReserve } from '../models/lending';
-import { useLendingReserves } from './useLendingReserves';
-import { useEffect, useMemo, useState } from 'react';
-import { useMarkets } from '../contexts/market';
-import { calculateCollateralBalance } from './useCollateralBalance';
-import { MintInfo } from '@solana/spl-token';
-
import {
contexts,
- utils,
+ fromLamports,
+ getTokenName,
ParsedAccount,
TokenAccount,
- hooks,
+ useUserAccounts,
} from '@oyster/common';
+import { MintInfo } from '@solana/spl-token';
+import { useEffect, useMemo, useState } from 'react';
+import { useMarkets } from '../contexts/market';
+import { calculateDepositAPY, Reserve } from '../models';
+import { calculateCollateralBalance } from './useCollateralBalance';
+import { useLendingReserves } from './useLendingReserves';
+
const { cache } = contexts.Accounts;
const { useConnectionConfig } = contexts.Connection;
-const { fromLamports, getTokenName } = utils;
-const { useUserAccounts } = hooks;
export interface UserDeposit {
account: TokenAccount;
@@ -26,7 +25,7 @@ export interface UserDeposit {
name: string;
precision: number;
};
- reserve: ParsedAccount;
+ reserve: ParsedAccount;
}
export function useUserDeposits(exclude?: Set, include?: Set) {
@@ -44,16 +43,16 @@ export function useUserDeposits(exclude?: Set, include?: Set) {
}
if (!include || include.has(id)) {
- result.set(item.info.collateralMint.toBase58(), item);
+ result.set(item.info.collateral.mint.toBase58(), item);
}
return result;
- }, new Map>());
+ }, new Map>());
}, [reserveAccounts, exclude, include]);
useEffect(() => {
const activeMarkets = new Set(
- reserveAccounts.map(r => r.info.dexMarket.toBase58()),
+ reserveAccounts.map(r => r.info.liquidity.aggregator.toBase58()),
);
const userDepositsFactory = () => {
@@ -62,10 +61,10 @@ export function useUserDeposits(exclude?: Set, include?: Set) {
.map(item => {
const reserve = reservesByCollateralMint.get(
item?.info.mint.toBase58(),
- ) as ParsedAccount;
+ ) as ParsedAccount;
let collateralMint = cache.get(
- reserve.info.collateralMint,
+ reserve.info.collateral.mint,
) as ParsedAccount;
const amountLamports = calculateCollateralBalance(
@@ -73,7 +72,7 @@ export function useUserDeposits(exclude?: Set, include?: Set) {
item?.info.amount.toNumber(),
);
const amount = fromLamports(amountLamports, collateralMint?.info);
- const price = midPriceInUSD(reserve.info.liquidityMint.toBase58());
+ const price = midPriceInUSD(reserve.info.liquidity.mint.toBase58());
const amountInQuote = price * amount;
return {
@@ -82,7 +81,7 @@ export function useUserDeposits(exclude?: Set, include?: Set) {
amount,
amountInQuote: amountInQuote,
apy: calculateDepositAPY(reserve.info),
- name: getTokenName(tokenMap, reserve.info.liquidityMint),
+ name: getTokenName(tokenMap, reserve.info.liquidity.mint),
},
reserve,
} as UserDeposit;
diff --git a/packages/lending/src/hooks/useUserObligationByReserve.ts b/packages/lending/src/hooks/useUserObligationByReserve.ts
index de127c6f..9fd81cca 100644
--- a/packages/lending/src/hooks/useUserObligationByReserve.ts
+++ b/packages/lending/src/hooks/useUserObligationByReserve.ts
@@ -1,10 +1,10 @@
+import { PublicKey } from '@solana/web3.js';
import { useMemo } from 'react';
import { useUserObligations } from './useUserObligations';
-import { PublicKey } from '@solana/web3.js';
export function useUserObligationByReserve(
borrowReserve?: string | PublicKey,
- collateralReserve?: string | PublicKey,
+ depositReserve?: string | PublicKey,
) {
const { userObligations } = useUserObligations();
@@ -13,20 +13,22 @@ export function useUserObligationByReserve(
typeof borrowReserve === 'string'
? borrowReserve
: borrowReserve?.toBase58();
- const collateralId =
- typeof collateralReserve === 'string'
- ? collateralReserve
- : collateralReserve?.toBase58();
+ const depositId =
+ typeof depositReserve === 'string'
+ ? depositReserve
+ : depositReserve?.toBase58();
return userObligations.filter(item =>
- borrowId && collateralId
- ? item.obligation.info.borrowReserve.toBase58() === borrowId &&
- item.obligation.info.collateralReserve.toBase58() === collateralId
+ borrowId && depositId
+ ? item.obligation.info.borrows.borrowReserve.toBase58() === borrowId &&
+ item.obligation.info.deposits.depositReserve.toBase58() === depositId
: (borrowId &&
- item.obligation.info.borrowReserve.toBase58() === borrowId) ||
- (collateralId &&
- item.obligation.info.collateralReserve.toBase58() === collateralId),
+ item.obligation.info.borrows.borrowReserve.toBase58() ===
+ borrowId) ||
+ (depositId &&
+ item.obligation.info.deposits.depositReserve.toBase58() ===
+ depositId),
);
- }, [borrowReserve, collateralReserve, userObligations]);
+ }, [borrowReserve, depositReserve, userObligations]);
return {
userObligationsByReserve,
diff --git a/packages/lending/src/hooks/useUserObligations.ts b/packages/lending/src/hooks/useUserObligations.ts
index 2672eb41..2264e85e 100644
--- a/packages/lending/src/hooks/useUserObligations.ts
+++ b/packages/lending/src/hooks/useUserObligations.ts
@@ -1,6 +1,7 @@
+import { hooks, TokenAccount } from '@oyster/common';
import { useMemo } from 'react';
import { useEnrichedLendingObligations } from './useEnrichedLendingObligations';
-import { TokenAccount, hooks } from '@oyster/common';
+
const { useUserAccounts } = hooks;
export function useUserObligations() {
diff --git a/packages/lending/src/index.tsx b/packages/lending/src/index.tsx
index 63d751b4..a54e5fa5 100644
--- a/packages/lending/src/index.tsx
+++ b/packages/lending/src/index.tsx
@@ -1,15 +1,15 @@
-import "./wdyr";
+import React from 'react';
+import ReactDOM from 'react-dom';
+import App from './App';
+import './index.css';
+import * as serviceWorker from './serviceWorker';
+import './wdyr';
-import React from "react";
-import ReactDOM from "react-dom";
-import "./index.css";
-import App from "./App";
-import * as serviceWorker from "./serviceWorker";
ReactDOM.render(
,
- document.getElementById("root")
+ document.getElementById('root'),
);
// If you want your app to work offline and load faster, you can change
diff --git a/packages/lending/src/models/dex/market.ts b/packages/lending/src/models/dex/market.ts
index 54aee094..68e582d0 100644
--- a/packages/lending/src/models/dex/market.ts
+++ b/packages/lending/src/models/dex/market.ts
@@ -1,6 +1,7 @@
import { contexts, ParsedAccountBase } from '@oyster/common';
import { Market, MARKETS, Orderbook } from '@project-serum/serum';
import { AccountInfo, PublicKey } from '@solana/web3.js';
+
const { MintParser, cache } = contexts.Accounts;
export const OrderBookParser = (id: PublicKey, acc: AccountInfo) => {
@@ -39,7 +40,7 @@ export const DexMarketParser = (
} as ParsedAccountBase;
cache.registerParser(details.info.baseMint, MintParser);
- cache.registerParser(details.info.quoteMint, MintParser);
+ cache.registerParser(details.info.quoteTokenMint, MintParser);
cache.registerParser(details.info.bids, OrderBookParser);
cache.registerParser(details.info.asks, OrderBookParser);
diff --git a/packages/lending/src/models/index.ts b/packages/lending/src/models/index.ts
index fb37793e..e2e28868 100644
--- a/packages/lending/src/models/index.ts
+++ b/packages/lending/src/models/index.ts
@@ -1,3 +1,4 @@
-export * from './lending';
+export * from './instructions';
+export * from './state';
export * from './pool';
export * from './totals';
diff --git a/packages/lending/src/models/instructions/borrowObligationLiquidity.ts b/packages/lending/src/models/instructions/borrowObligationLiquidity.ts
new file mode 100644
index 00000000..562aa1e3
--- /dev/null
+++ b/packages/lending/src/models/instructions/borrowObligationLiquidity.ts
@@ -0,0 +1,115 @@
+import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@oyster/common';
+import {
+ PublicKey,
+ SYSVAR_CLOCK_PUBKEY,
+ TransactionInstruction,
+} from '@solana/web3.js';
+import BN from 'bn.js';
+import * as BufferLayout from 'buffer-layout';
+import * as Layout from '../../utils/layout';
+import { calculateUtilizationRatio, Reserve } from '../state/reserve';
+import { LendingInstruction } from './instruction';
+
+// @FIXME: remove
+export enum BorrowAmountType {
+ LiquidityBorrowAmount = 0,
+ CollateralDepositAmount = 1,
+}
+
+/// Borrow liquidity from a reserve by depositing collateral tokens. Requires a refreshed
+/// obligation and reserve.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Source borrow reserve liquidity supply SPL Token account.
+/// 1. `[writable]` Destination liquidity token account.
+/// Minted by borrow reserve liquidity mint.
+/// 2. `[writable]` Borrow reserve account - refreshed.
+/// 3. `[writable]` Borrow reserve liquidity fee receiver account.
+/// Must be the fee account specified at InitReserve.
+/// 4. `[writable]` Obligation account - refreshed.
+/// 5. `[]` Lending market account.
+/// 6. `[]` Derived lending market authority.
+/// 7. `[signer]` Obligation owner.
+/// 8. `[]` Clock sysvar.
+/// 9. `[]` Token program id.
+/// 10 `[optional, writable]` Host fee receiver account.
+export const borrowObligationLiquidityInstruction = (
+ liquidityAmount: number | BN,
+ sourceLiquidity: PublicKey,
+ destinationLiquidity: PublicKey,
+ borrowReserve: PublicKey,
+ borrowReserveLiquidityFeeReceiver: PublicKey,
+ obligation: PublicKey,
+ lendingMarket: PublicKey,
+ lendingMarketAuthority: PublicKey,
+ obligationOwner: PublicKey,
+ hostFeeReceiver?: PublicKey,
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([
+ BufferLayout.u8('instruction'),
+ Layout.uint64('liquidityAmount'),
+ ]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode(
+ {
+ instruction: LendingInstruction.BorrowObligationLiquidity,
+ liquidityAmount: new BN(liquidityAmount),
+ },
+ data,
+ );
+
+ const keys = [
+ { pubkey: sourceLiquidity, isSigner: false, isWritable: true },
+ { pubkey: destinationLiquidity, isSigner: false, isWritable: true },
+ { pubkey: borrowReserve, isSigner: false, isWritable: true },
+ {
+ pubkey: borrowReserveLiquidityFeeReceiver,
+ isSigner: false,
+ isWritable: true,
+ },
+ { pubkey: obligation, isSigner: false, isWritable: true },
+ { pubkey: lendingMarket, isSigner: false, isWritable: false },
+ { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
+ { pubkey: obligationOwner, isSigner: true, isWritable: false },
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
+ ];
+
+ if (hostFeeReceiver) {
+ keys.push({ pubkey: hostFeeReceiver, isSigner: false, isWritable: true });
+ }
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
+
+// deposit APY utilization currentUtilizationRate * borrowAPY
+
+export const calculateBorrowAPY = (reserve: Reserve) => {
+ const currentUtilization = calculateUtilizationRatio(reserve);
+ const optimalUtilization = reserve.config.optimalUtilizationRate / 100;
+
+ let borrowAPY;
+ if (optimalUtilization === 1.0 || currentUtilization < optimalUtilization) {
+ const normalizedFactor = currentUtilization / optimalUtilization;
+ const optimalBorrowRate = reserve.config.optimalBorrowRate / 100;
+ const minBorrowRate = reserve.config.minBorrowRate / 100;
+ borrowAPY =
+ normalizedFactor * (optimalBorrowRate - minBorrowRate) + minBorrowRate;
+ } else {
+ const normalizedFactor =
+ (currentUtilization - optimalUtilization) / (1 - optimalUtilization);
+ const optimalBorrowRate = reserve.config.optimalBorrowRate / 100;
+ const maxBorrowRate = reserve.config.maxBorrowRate / 100;
+ borrowAPY =
+ normalizedFactor * (maxBorrowRate - optimalBorrowRate) +
+ optimalBorrowRate;
+ }
+
+ return borrowAPY;
+};
diff --git a/packages/lending/src/models/instructions/depositObligationCollateral.ts b/packages/lending/src/models/instructions/depositObligationCollateral.ts
new file mode 100644
index 00000000..d65bb175
--- /dev/null
+++ b/packages/lending/src/models/instructions/depositObligationCollateral.ts
@@ -0,0 +1,71 @@
+import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@oyster/common';
+import {
+ PublicKey,
+ SYSVAR_CLOCK_PUBKEY,
+ TransactionInstruction,
+} from '@solana/web3.js';
+import BN from 'bn.js';
+import * as BufferLayout from 'buffer-layout';
+import * as Layout from './../../utils/layout';
+import { LendingInstruction } from './instruction';
+
+/// Deposit collateral to an obligation. Requires a refreshed reserve.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Source collateral token account.
+/// Minted by deposit reserve collateral mint.
+/// $authority can transfer $collateral_amount.
+/// 1. `[writable]` Destination deposit reserve collateral supply SPL Token account.
+/// 2. `[]` Deposit reserve account - refreshed.
+/// 3. `[writable]` Obligation account.
+/// 4. `[]` Lending market account.
+/// 5. `[]` Derived lending market authority.
+/// 6. `[signer]` Obligation owner.
+/// 7. `[signer]` User transfer authority ($authority).
+/// 8. `[]` Clock sysvar.
+/// 9. `[]` Token program id.
+export const depositObligationCollateralInstruction = (
+ collateralAmount: number | BN,
+ sourceCollateral: PublicKey,
+ destinationCollateral: PublicKey,
+ depositReserve: PublicKey,
+ obligation: PublicKey,
+ lendingMarket: PublicKey,
+ lendingMarketAuthority: PublicKey,
+ obligationOwner: PublicKey,
+ transferAuthority: PublicKey,
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([
+ BufferLayout.u8('instruction'),
+ Layout.uint64('collateralAmount'),
+ ]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode(
+ {
+ instruction: LendingInstruction.DepositObligationCollateral,
+ collateralAmount: new BN(collateralAmount),
+ },
+ data,
+ );
+
+ const keys = [
+ { pubkey: sourceCollateral, isSigner: false, isWritable: true },
+ { pubkey: destinationCollateral, isSigner: false, isWritable: true },
+ { pubkey: depositReserve, isSigner: false, isWritable: false },
+ { pubkey: obligation, isSigner: false, isWritable: true },
+ { pubkey: lendingMarket, isSigner: false, isWritable: false },
+ { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
+ { pubkey: obligationOwner, isSigner: true, isWritable: false },
+ { pubkey: transferAuthority, isSigner: true, isWritable: false },
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
+ ];
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
diff --git a/packages/lending/src/models/lending/deposit.ts b/packages/lending/src/models/instructions/depositReserveLiquidity.ts
similarity index 53%
rename from packages/lending/src/models/lending/deposit.ts
rename to packages/lending/src/models/instructions/depositReserveLiquidity.ts
index 61e962e5..8551f436 100644
--- a/packages/lending/src/models/lending/deposit.ts
+++ b/packages/lending/src/models/instructions/depositReserveLiquidity.ts
@@ -1,3 +1,4 @@
+import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@oyster/common';
import {
PublicKey,
SYSVAR_CLOCK_PUBKEY,
@@ -5,36 +6,37 @@ import {
} from '@solana/web3.js';
import BN from 'bn.js';
import * as BufferLayout from 'buffer-layout';
-import { calculateBorrowAPY } from './borrow';
-import { LendingInstruction } from './lending';
-import { calculateUtilizationRatio, LendingReserve } from './reserve';
-import { utils } from '@oyster/common';
import * as Layout from '../../utils/layout';
+import { calculateUtilizationRatio, Reserve } from '../state/reserve';
+import { calculateBorrowAPY } from './borrowObligationLiquidity';
+import { LendingInstruction } from './instruction';
-const { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } = utils;
-/// Deposit liquidity into a reserve. The output is a collateral token representing ownership
+/// Deposit liquidity into a reserve in exchange for collateral. Collateral represents a share
/// of the reserve liquidity pool.
///
-/// 0. `[writable]` Source liquidity token account. $authority can transfer $liquidity_amount
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Source liquidity token account.
+/// $authority can transfer $liquidity_amount.
/// 1. `[writable]` Destination collateral token account.
/// 2. `[writable]` Reserve account.
/// 3. `[writable]` Reserve liquidity supply SPL Token account.
/// 4. `[writable]` Reserve collateral SPL Token mint.
/// 5. `[]` Lending market account.
/// 6. `[]` Derived lending market authority.
-/// 7. `[]` User transfer authority ($authority).
-/// 8. `[]` Clock sysvar
-/// 9. '[]` Token program id
-export const depositInstruction = (
+/// 7. `[signer]` User transfer authority ($authority).
+/// 8. `[]` Clock sysvar.
+/// 9. `[]` Token program id.
+export const depositReserveLiquidityInstruction = (
liquidityAmount: number | BN,
- from: PublicKey, // Liquidity input SPL Token account. $authority can transfer $liquidity_amount
- to: PublicKey, // Collateral output SPL Token account,
+ sourceLiquidity: PublicKey,
+ destinationCollateral: PublicKey,
+ reserve: PublicKey,
+ reserveLiquiditySupply: PublicKey,
+ reserveCollateralMint: PublicKey,
lendingMarket: PublicKey,
- reserveAuthority: PublicKey,
+ lendingMarketAuthority: PublicKey,
transferAuthority: PublicKey,
- reserveAccount: PublicKey,
- reserveSupply: PublicKey,
- collateralMint: PublicKey,
): TransactionInstruction => {
const dataLayout = BufferLayout.struct([
BufferLayout.u8('instruction'),
@@ -51,17 +53,18 @@ export const depositInstruction = (
);
const keys = [
- { pubkey: from, isSigner: false, isWritable: true },
- { pubkey: to, isSigner: false, isWritable: true },
- { pubkey: reserveAccount, isSigner: false, isWritable: true },
- { pubkey: reserveSupply, isSigner: false, isWritable: true },
- { pubkey: collateralMint, isSigner: false, isWritable: true },
+ { pubkey: sourceLiquidity, isSigner: false, isWritable: true },
+ { pubkey: destinationCollateral, isSigner: false, isWritable: true },
+ { pubkey: reserve, isSigner: false, isWritable: true },
+ { pubkey: reserveLiquiditySupply, isSigner: false, isWritable: true },
+ { pubkey: reserveCollateralMint, isSigner: false, isWritable: true },
{ pubkey: lendingMarket, isSigner: false, isWritable: false },
- { pubkey: reserveAuthority, isSigner: false, isWritable: false },
+ { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
{ pubkey: transferAuthority, isSigner: true, isWritable: false },
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
];
+
return new TransactionInstruction({
keys,
programId: LENDING_PROGRAM_ID,
@@ -69,7 +72,7 @@ export const depositInstruction = (
});
};
-export const calculateDepositAPY = (reserve: LendingReserve) => {
+export const calculateDepositAPY = (reserve: Reserve) => {
const currentUtilization = calculateUtilizationRatio(reserve);
const borrowAPY = calculateBorrowAPY(reserve);
diff --git a/packages/lending/src/models/instructions/index.ts b/packages/lending/src/models/instructions/index.ts
new file mode 100644
index 00000000..38d8ce46
--- /dev/null
+++ b/packages/lending/src/models/instructions/index.ts
@@ -0,0 +1,13 @@
+export * from './borrowObligationLiquidity';
+export * from './depositObligationCollateral';
+export * from './depositReserveLiquidity';
+export * from './initLendingMarket';
+export * from './initObligation';
+export * from './initReserve';
+export * from './instruction';
+export * from './liquidateObligation';
+export * from './redeemReserveCollateral';
+export * from './refreshObligation';
+export * from './refreshReserve';
+export * from './repayObligationLiquidity';
+export * from './withdrawObligationCollateral';
diff --git a/packages/lending/src/models/instructions/initLendingMarket.ts b/packages/lending/src/models/instructions/initLendingMarket.ts
new file mode 100644
index 00000000..377eabfa
--- /dev/null
+++ b/packages/lending/src/models/instructions/initLendingMarket.ts
@@ -0,0 +1,54 @@
+import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@oyster/common';
+import {
+ PublicKey,
+ SYSVAR_RENT_PUBKEY,
+ TransactionInstruction,
+} from '@solana/web3.js';
+import * as BufferLayout from 'buffer-layout';
+import * as Layout from '../../utils/layout';
+import { LendingInstruction } from './instruction';
+
+/// Initializes a new lending market.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Lending market account - uninitialized.
+/// 1. `[]` Quote currency SPL Token mint.
+/// 2. `[]` Rent sysvar.
+/// 3. `[]` Token program id.
+// InitLendingMarket {
+// /// Owner authority which can add new reserves
+// owner: Pubkey,
+// },
+export const initLendingMarketInstruction = (
+ owner: PublicKey,
+ lendingMarket: PublicKey,
+ quoteTokenMint: PublicKey,
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([
+ BufferLayout.u8('instruction'),
+ Layout.publicKey('owner'),
+ ]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode(
+ {
+ instruction: LendingInstruction.InitLendingMarket,
+ owner,
+ },
+ data,
+ );
+
+ const keys = [
+ { pubkey: lendingMarket, isSigner: false, isWritable: true },
+ { pubkey: quoteTokenMint, isSigner: false, isWritable: false },
+ { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
+ ];
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
diff --git a/packages/lending/src/models/instructions/initObligation.ts b/packages/lending/src/models/instructions/initObligation.ts
new file mode 100644
index 00000000..bd9d3099
--- /dev/null
+++ b/packages/lending/src/models/instructions/initObligation.ts
@@ -0,0 +1,45 @@
+import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@oyster/common';
+import {
+ PublicKey,
+ SYSVAR_CLOCK_PUBKEY,
+ SYSVAR_RENT_PUBKEY,
+ TransactionInstruction,
+} from '@solana/web3.js';
+import * as BufferLayout from 'buffer-layout';
+import { LendingInstruction } from './instruction';
+
+/// Initializes a new lending market obligation.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Obligation account - uninitialized.
+/// 1. `[]` Lending market account.
+/// 2. `[signer]` Obligation owner.
+/// 3. `[]` Clock sysvar.
+/// 4. `[]` Rent sysvar.
+/// 5. `[]` Token program id.
+export const initObligationInstruction = (
+ obligation: PublicKey,
+ lendingMarket: PublicKey,
+ obligationOwner: PublicKey,
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode({ instruction: LendingInstruction.InitObligation }, data);
+
+ const keys = [
+ { pubkey: obligation, isSigner: false, isWritable: true },
+ { pubkey: lendingMarket, isSigner: false, isWritable: false },
+ { pubkey: obligationOwner, isSigner: true, isWritable: false },
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
+ { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
+ ];
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
diff --git a/packages/lending/src/models/instructions/initReserve.ts b/packages/lending/src/models/instructions/initReserve.ts
new file mode 100644
index 00000000..5b5e7142
--- /dev/null
+++ b/packages/lending/src/models/instructions/initReserve.ts
@@ -0,0 +1,104 @@
+import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@oyster/common';
+import {
+ PublicKey,
+ SYSVAR_CLOCK_PUBKEY,
+ SYSVAR_RENT_PUBKEY,
+ TransactionInstruction,
+} from '@solana/web3.js';
+import BN from 'bn.js';
+import * as BufferLayout from 'buffer-layout';
+import * as Layout from '../../utils/layout';
+import { LendingInstruction } from './instruction';
+
+/// Initializes a new lending market reserve.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Source liquidity token account.
+/// $authority can transfer $liquidity_amount.
+/// 1. `[writable]` Destination collateral token account - uninitialized.
+/// 2. `[writable]` Reserve account - uninitialized.
+/// 3. `[]` Reserve liquidity SPL Token mint.
+/// 4. `[writable]` Reserve liquidity supply SPL Token account - uninitialized.
+/// 5. `[writable]` Reserve liquidity fee receiver - uninitialized.
+/// 6. `[writable]` Reserve collateral SPL Token mint - uninitialized.
+/// 7. `[writable]` Reserve collateral token supply - uninitialized.
+/// 8. `[]` Quote currency SPL Token mint.
+/// 9. `[]` Lending market account.
+/// 10 `[]` Derived lending market authority.
+/// 11 `[signer]` Lending market owner.
+/// 12 `[signer]` User transfer authority ($authority).
+/// 13 `[]` Clock sysvar.
+/// 13 `[]` Rent sysvar.
+/// 14 `[]` Token program id.
+/// 15 `[optional]` Reserve liquidity aggregator account.
+/// Not required for quote currency reserves.
+/// Must match base and quote currency mint, and quote currency decimals.
+// InitReserve {
+// /// Initial amount of liquidity to deposit into the new reserve
+// liquidity_amount: u64,
+// /// Reserve configuration values
+// config: ReserveConfig,
+// },
+export const initReserveInstruction = (
+ liquidityAmount: number | BN,
+ // @FIXME: reserve config
+ maxUtilizationRate: number,
+ sourceLiquidity: PublicKey,
+ destinationCollateral: PublicKey,
+ reserve: PublicKey,
+ liquidityMint: PublicKey,
+ liquiditySupply: PublicKey,
+ liquidityFeeReceiver: PublicKey,
+ collateralMint: PublicKey,
+ collateralSupply: PublicKey,
+ lendingMarket: PublicKey,
+ lendingMarketAuthority: PublicKey,
+ lendingMarketOwner: PublicKey,
+ transferAuthority: PublicKey,
+ aggregator?: PublicKey,
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([
+ BufferLayout.u8('instruction'),
+ Layout.uint64('liquidityAmount'),
+ // @FIXME: reserve config
+ BufferLayout.u8('maxUtilizationRate'),
+ ]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode(
+ {
+ instruction: LendingInstruction.InitReserve,
+ liquidityAmount: new BN(liquidityAmount),
+ maxUtilizationRate,
+ },
+ data,
+ );
+
+ const keys = [
+ { pubkey: sourceLiquidity, isSigner: false, isWritable: true },
+ { pubkey: destinationCollateral, isSigner: false, isWritable: true },
+ { pubkey: reserve, isSigner: false, isWritable: true },
+ { pubkey: liquidityMint, isSigner: false, isWritable: false },
+ { pubkey: liquiditySupply, isSigner: false, isWritable: true },
+ { pubkey: liquidityFeeReceiver, isSigner: false, isWritable: true },
+ { pubkey: collateralMint, isSigner: false, isWritable: true },
+ { pubkey: collateralSupply, isSigner: false, isWritable: true },
+ { pubkey: lendingMarket, isSigner: false, isWritable: true },
+ { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
+ { pubkey: transferAuthority, isSigner: true, isWritable: false },
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
+ { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
+ ];
+
+ if (aggregator) {
+ keys.push({ pubkey: aggregator, isSigner: false, isWritable: false });
+ }
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
diff --git a/packages/lending/src/models/instructions/instruction.ts b/packages/lending/src/models/instructions/instruction.ts
new file mode 100644
index 00000000..d342c072
--- /dev/null
+++ b/packages/lending/src/models/instructions/instruction.ts
@@ -0,0 +1,15 @@
+export enum LendingInstruction {
+ InitLendingMarket = 0,
+ SetLendingMarketOwner = 1,
+ InitReserve = 2,
+ RefreshReserve = 3,
+ DepositReserveLiquidity = 4,
+ RedeemReserveCollateral = 5,
+ InitObligation = 6,
+ RefreshObligation = 7,
+ DepositObligationCollateral = 8,
+ WithdrawObligationCollateral = 9,
+ BorrowObligationLiquidity = 10,
+ RepayObligationLiquidity = 11,
+ LiquidateObligation = 12,
+}
diff --git a/packages/lending/src/models/lending/liquidate.ts b/packages/lending/src/models/instructions/liquidateObligation.ts
similarity index 51%
rename from packages/lending/src/models/lending/liquidate.ts
rename to packages/lending/src/models/instructions/liquidateObligation.ts
index 73012440..b16e6cc3 100644
--- a/packages/lending/src/models/lending/liquidate.ts
+++ b/packages/lending/src/models/instructions/liquidateObligation.ts
@@ -1,48 +1,46 @@
+import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@oyster/common';
import {
PublicKey,
SYSVAR_CLOCK_PUBKEY,
TransactionInstruction,
} from '@solana/web3.js';
import BN from 'bn.js';
-import { LendingInstruction } from './lending';
import * as BufferLayout from 'buffer-layout';
-import { utils } from '@oyster/common';
import * as Layout from '../../utils/layout';
+import { LendingInstruction } from './instruction';
-const { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } = utils;
-/// Purchase collateral tokens at a discount rate if the chosen obligation is unhealthy.
+/// Repay borrowed liquidity to a reserve to receive collateral at a discount from an unhealthy
+/// obligation. Requires a refreshed obligation and reserves.
///
-/// 0. `[writable]` Source liquidity token account, minted by repay reserve liquidity mint
-/// $authority can transfer $collateral_amount
-/// 1. `[writable]` Destination collateral token account, minted by withdraw reserve collateral mint
-/// 2. `[]` Repay reserve account.
-/// 3. `[writable]` Repay reserve liquidity supply SPL Token account
-/// 4. `[writable]` Withdraw reserve account.
-/// 5. `[writable]` Withdraw reserve collateral supply SPL Token account
-/// 6. `[writable]` Obligation - initialized
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Source liquidity token account.
+/// Minted by repay reserve liquidity mint.
+/// $authority can transfer $liquidity_amount.
+/// 1. `[writable]` Destination collateral token account.
+/// Minted by withdraw reserve collateral mint.
+/// 2. `[writable]` Repay reserve account - refreshed.
+/// 3. `[writable]` Repay reserve liquidity supply SPL Token account.
+/// 4. `[]` Withdraw reserve account - refreshed.
+/// 5. `[writable]` Withdraw reserve collateral supply SPL Token account.
+/// 6. `[writable]` Obligation account - refreshed.
/// 7. `[]` Lending market account.
/// 8. `[]` Derived lending market authority.
-/// 9. `[]` User transfer authority ($authority).
-/// 10 `[]` Dex market
-/// 11 `[]` Dex market order book side
-/// 12 `[]` Temporary memory
-/// 13 `[]` Clock sysvar
-/// 14 `[]` Token program id
-export const liquidateInstruction = (
+/// 9. `[signer]` User transfer authority ($authority).
+/// 10 `[]` Clock sysvar.
+/// 11 `[]` Token program id.
+export const liquidateObligationInstruction = (
liquidityAmount: number | BN,
- from: PublicKey, // Liquidity input SPL Token account. $authority can transfer $liquidity_amount
- to: PublicKey, // Collateral output SPL Token account,
- repayReserveAccount: PublicKey,
+ sourceLiquidity: PublicKey,
+ destinationCollateral: PublicKey,
+ repayReserve: PublicKey,
repayReserveLiquiditySupply: PublicKey,
withdrawReserve: PublicKey,
withdrawReserveCollateralSupply: PublicKey,
obligation: PublicKey,
lendingMarket: PublicKey,
- authority: PublicKey,
+ lendingMarketAuthority: PublicKey,
transferAuthority: PublicKey,
- dexMarket: PublicKey,
- dexOrderBookSide: PublicKey,
- memory: PublicKey,
): TransactionInstruction => {
const dataLayout = BufferLayout.struct([
BufferLayout.u8('instruction'),
@@ -59,33 +57,24 @@ export const liquidateInstruction = (
);
const keys = [
- { pubkey: from, isSigner: false, isWritable: true },
- { pubkey: to, isSigner: false, isWritable: true },
-
- { pubkey: repayReserveAccount, isSigner: false, isWritable: true },
+ { pubkey: sourceLiquidity, isSigner: false, isWritable: true },
+ { pubkey: destinationCollateral, isSigner: false, isWritable: true },
+ { pubkey: repayReserve, isSigner: false, isWritable: true },
{ pubkey: repayReserveLiquiditySupply, isSigner: false, isWritable: true },
-
{ pubkey: withdrawReserve, isSigner: false, isWritable: false },
{
pubkey: withdrawReserveCollateralSupply,
isSigner: false,
isWritable: true,
},
-
{ pubkey: obligation, isSigner: false, isWritable: true },
-
{ pubkey: lendingMarket, isSigner: false, isWritable: false },
- { pubkey: authority, isSigner: false, isWritable: false },
+ { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
{ pubkey: transferAuthority, isSigner: true, isWritable: false },
-
- { pubkey: dexMarket, isSigner: false, isWritable: false },
- { pubkey: dexOrderBookSide, isSigner: false, isWritable: false },
-
- { pubkey: memory, isSigner: false, isWritable: false },
-
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
];
+
return new TransactionInstruction({
keys,
programId: LENDING_PROGRAM_ID,
diff --git a/packages/lending/src/models/instructions/redeemReserveCollateral.ts b/packages/lending/src/models/instructions/redeemReserveCollateral.ts
new file mode 100644
index 00000000..d95f4b17
--- /dev/null
+++ b/packages/lending/src/models/instructions/redeemReserveCollateral.ts
@@ -0,0 +1,70 @@
+import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@oyster/common';
+import {
+ PublicKey,
+ SYSVAR_CLOCK_PUBKEY,
+ TransactionInstruction,
+} from '@solana/web3.js';
+import BN from 'bn.js';
+import * as BufferLayout from 'buffer-layout';
+import * as Layout from '../../utils/layout';
+import { LendingInstruction } from './instruction';
+
+/// Redeem collateral from a reserve in exchange for liquidity.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Source collateral token account.
+/// $authority can transfer $collateral_amount.
+/// 1. `[writable]` Destination liquidity token account.
+/// 2. `[writable]` Reserve account.
+/// 3. `[writable]` Reserve collateral SPL Token mint.
+/// 4. `[writable]` Reserve liquidity supply SPL Token account.
+/// 5. `[]` Lending market account.
+/// 6. `[]` Derived lending market authority.
+/// 7. `[signer]` User transfer authority ($authority).
+/// 8. `[]` Clock sysvar.
+/// 9. `[]` Token program id.
+export const redeemReserveCollateral = (
+ collateralAmount: number | BN,
+ sourceCollateral: PublicKey,
+ destinationLiquidity: PublicKey,
+ reserve: PublicKey,
+ reserveCollateralMint: PublicKey,
+ reserveLiquiditySupply: PublicKey,
+ lendingMarket: PublicKey,
+ lendingMarketAuthority: PublicKey,
+ transferAuthority: PublicKey,
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([
+ BufferLayout.u8('instruction'),
+ Layout.uint64('collateralAmount'),
+ ]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode(
+ {
+ instruction: LendingInstruction.RedeemReserveCollateral,
+ collateralAmount: new BN(collateralAmount),
+ },
+ data,
+ );
+
+ const keys = [
+ { pubkey: sourceCollateral, isSigner: false, isWritable: true },
+ { pubkey: destinationLiquidity, isSigner: false, isWritable: true },
+ { pubkey: reserve, isSigner: false, isWritable: true },
+ { pubkey: reserveCollateralMint, isSigner: false, isWritable: true },
+ { pubkey: reserveLiquiditySupply, isSigner: false, isWritable: true },
+ { pubkey: lendingMarket, isSigner: false, isWritable: false },
+ { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
+ { pubkey: transferAuthority, isSigner: true, isWritable: false },
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
+ ];
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
diff --git a/packages/lending/src/models/instructions/refreshObligation.ts b/packages/lending/src/models/instructions/refreshObligation.ts
new file mode 100644
index 00000000..7ab24461
--- /dev/null
+++ b/packages/lending/src/models/instructions/refreshObligation.ts
@@ -0,0 +1,51 @@
+import { LENDING_PROGRAM_ID } from '@oyster/common';
+import {
+ PublicKey,
+ SYSVAR_CLOCK_PUBKEY,
+ TransactionInstruction,
+} from '@solana/web3.js';
+import BufferLayout from 'buffer-layout';
+import { LendingInstruction } from './instruction';
+
+/// Refresh an obligation's accrued interest and collateral and liquidity prices. Requires
+/// refreshed reserves, as all obligation collateral deposit reserves in order, followed by all
+/// liquidity borrow reserves in order.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Obligation account.
+/// 1. `[]` Clock sysvar.
+/// .. `[]` Collateral deposit reserve accounts - refreshed, all, in order.
+/// .. `[]` Liquidity borrow reserve accounts - refreshed, all, in order.
+export const refreshObligationInstruction = (
+ obligation: PublicKey,
+ depositReserves: PublicKey[],
+ borrowReserves: PublicKey[],
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode(
+ { instruction: LendingInstruction.RefreshObligation },
+ data,
+ );
+
+ const keys = [
+ { pubkey: obligation, isSigner: false, isWritable: true },
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
+ ];
+
+ for (const depositReserve of depositReserves) {
+ keys.push({ pubkey: depositReserve, isSigner: false, isWritable: false });
+ }
+
+ for (const borrowReserve of borrowReserves) {
+ keys.push({ pubkey: borrowReserve, isSigner: false, isWritable: false });
+ }
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
diff --git a/packages/lending/src/models/instructions/refreshReserve.ts b/packages/lending/src/models/instructions/refreshReserve.ts
new file mode 100644
index 00000000..3e74c96d
--- /dev/null
+++ b/packages/lending/src/models/instructions/refreshReserve.ts
@@ -0,0 +1,42 @@
+import { LENDING_PROGRAM_ID } from '@oyster/common';
+import {
+ PublicKey,
+ SYSVAR_CLOCK_PUBKEY,
+ TransactionInstruction,
+} from '@solana/web3.js';
+import * as BufferLayout from 'buffer-layout';
+import { LendingInstruction } from './instruction';
+
+/// Accrue interest and update market price of liquidity on a reserve.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Reserve account.
+/// 1. `[]` Clock sysvar.
+/// 2. `[optional]` Reserve liquidity aggregator account.
+/// Required if the reserve currency is not the lending market quote
+/// currency.
+export const refreshReserveInstruction = (
+ reserve: PublicKey,
+ aggregator?: PublicKey,
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode({ instruction: LendingInstruction.RefreshReserve }, data);
+
+ const keys = [
+ { pubkey: reserve, isSigner: false, isWritable: true },
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
+ ];
+
+ if (aggregator) {
+ keys.push({ pubkey: aggregator, isSigner: false, isWritable: false });
+ }
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
diff --git a/packages/lending/src/models/instructions/repayObligationLiquidity.ts b/packages/lending/src/models/instructions/repayObligationLiquidity.ts
new file mode 100644
index 00000000..f01952e9
--- /dev/null
+++ b/packages/lending/src/models/instructions/repayObligationLiquidity.ts
@@ -0,0 +1,68 @@
+import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@oyster/common';
+import {
+ PublicKey,
+ SYSVAR_CLOCK_PUBKEY,
+ TransactionInstruction,
+} from '@solana/web3.js';
+import BN from 'bn.js';
+import * as BufferLayout from 'buffer-layout';
+import * as Layout from '../../utils/layout';
+import { LendingInstruction } from './instruction';
+
+/// Repay borrowed liquidity to a reserve. Requires a refreshed obligation and reserve.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Source liquidity token account.
+/// Minted by repay reserve liquidity mint.
+/// $authority can transfer $liquidity_amount.
+/// 1. `[writable]` Destination repay reserve liquidity supply SPL Token account.
+/// 2. `[writable]` Repay reserve account - refreshed.
+/// 3. `[writable]` Obligation account - refreshed.
+/// 4. `[]` Lending market account.
+/// 5. `[]` Derived lending market authority.
+/// 6. `[signer]` User transfer authority ($authority).
+/// 7. `[]` Clock sysvar.
+/// 8. `[]` Token program id.
+export const repayObligationLiquidityInstruction = (
+ liquidityAmount: number | BN,
+ sourceLiquidity: PublicKey,
+ destinationLiquidity: PublicKey,
+ repayReserve: PublicKey,
+ obligation: PublicKey,
+ lendingMarket: PublicKey,
+ lendingMarketAuthority: PublicKey,
+ transferAuthority: PublicKey,
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([
+ BufferLayout.u8('instruction'),
+ Layout.uint64('liquidityAmount'),
+ ]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode(
+ {
+ instruction: LendingInstruction.RepayObligationLiquidity,
+ liquidityAmount: new BN(liquidityAmount),
+ },
+ data,
+ );
+
+ const keys = [
+ { pubkey: sourceLiquidity, isSigner: false, isWritable: true },
+ { pubkey: destinationLiquidity, isSigner: false, isWritable: true },
+ { pubkey: repayReserve, isSigner: false, isWritable: true },
+ { pubkey: obligation, isSigner: false, isWritable: true },
+ { pubkey: lendingMarket, isSigner: false, isWritable: false },
+ { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
+ { pubkey: transferAuthority, isSigner: true, isWritable: false },
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
+ ];
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
diff --git a/packages/lending/src/models/instructions/setLendingMarketOwner.ts b/packages/lending/src/models/instructions/setLendingMarketOwner.ts
new file mode 100644
index 00000000..edd28163
--- /dev/null
+++ b/packages/lending/src/models/instructions/setLendingMarketOwner.ts
@@ -0,0 +1,46 @@
+import { LENDING_PROGRAM_ID } from '@oyster/common';
+import { PublicKey, TransactionInstruction } from '@solana/web3.js';
+import * as BufferLayout from 'buffer-layout';
+import * as Layout from '../../utils/layout';
+import { LendingInstruction } from './instruction';
+
+/// Sets the new owner of a lending market.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Lending market account.
+/// 1. `[signer]` Current owner.
+// SetLendingMarketOwner {
+// /// The new owner
+// new_owner: Pubkey,
+// },
+export const setLendingMarketOwnerInstruction = (
+ newOwner: PublicKey,
+ lendingMarket: PublicKey,
+ currentOwner: PublicKey,
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([
+ BufferLayout.u8('instruction'),
+ Layout.publicKey('newOwner'),
+ ]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode(
+ {
+ instruction: LendingInstruction.SetLendingMarketOwner,
+ newOwner,
+ },
+ data,
+ );
+
+ const keys = [
+ { pubkey: lendingMarket, isSigner: false, isWritable: true },
+ { pubkey: currentOwner, isSigner: true, isWritable: false },
+ ];
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
diff --git a/packages/lending/src/models/instructions/withdrawObligationCollateral.ts b/packages/lending/src/models/instructions/withdrawObligationCollateral.ts
new file mode 100644
index 00000000..a5120094
--- /dev/null
+++ b/packages/lending/src/models/instructions/withdrawObligationCollateral.ts
@@ -0,0 +1,67 @@
+import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@oyster/common';
+import {
+ PublicKey,
+ SYSVAR_CLOCK_PUBKEY,
+ TransactionInstruction,
+} from '@solana/web3.js';
+import BN from 'bn.js';
+import * as BufferLayout from 'buffer-layout';
+import * as Layout from './../../utils/layout';
+import { LendingInstruction } from './instruction';
+
+/// Withdraw collateral from an obligation. Requires a refreshed obligation and reserve.
+///
+/// Accounts expected by this instruction:
+///
+/// 0. `[writable]` Source withdraw reserve collateral supply SPL Token account.
+/// 1. `[writable]` Destination collateral token account.
+/// Minted by withdraw reserve collateral mint.
+/// 2. `[]` Withdraw reserve account - refreshed.
+/// 3. `[writable]` Obligation account - refreshed.
+/// 4. `[]` Lending market account.
+/// 5. `[]` Derived lending market authority.
+/// 6. `[signer]` Obligation owner.
+/// 7. `[]` Clock sysvar.
+/// 8. `[]` Token program id.
+export const withdrawObligationCollateralInstruction = (
+ collateralAmount: number | BN,
+ sourceCollateral: PublicKey,
+ destinationCollateral: PublicKey,
+ withdrawReserve: PublicKey,
+ obligation: PublicKey,
+ lendingMarket: PublicKey,
+ lendingMarketAuthority: PublicKey,
+ obligationOwner: PublicKey,
+): TransactionInstruction => {
+ const dataLayout = BufferLayout.struct([
+ BufferLayout.u8('instruction'),
+ Layout.uint64('collateralAmount'),
+ ]);
+
+ const data = Buffer.alloc(dataLayout.span);
+ dataLayout.encode(
+ {
+ instruction: LendingInstruction.WithdrawObligationCollateral,
+ collateralAmount: new BN(collateralAmount),
+ },
+ data,
+ );
+
+ const keys = [
+ { pubkey: sourceCollateral, isSigner: false, isWritable: true },
+ { pubkey: destinationCollateral, isSigner: false, isWritable: true },
+ { pubkey: withdrawReserve, isSigner: false, isWritable: false },
+ { pubkey: obligation, isSigner: false, isWritable: true },
+ { pubkey: lendingMarket, isSigner: false, isWritable: false },
+ { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
+ { pubkey: obligationOwner, isSigner: true, isWritable: false },
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
+ ];
+
+ return new TransactionInstruction({
+ keys,
+ programId: LENDING_PROGRAM_ID,
+ data,
+ });
+};
diff --git a/packages/lending/src/models/lending/borrow.ts b/packages/lending/src/models/lending/borrow.ts
deleted file mode 100644
index 83d9f892..00000000
--- a/packages/lending/src/models/lending/borrow.ts
+++ /dev/null
@@ -1,149 +0,0 @@
-import {
- PublicKey,
- SYSVAR_CLOCK_PUBKEY,
- TransactionInstruction,
-} from '@solana/web3.js';
-import BN from 'bn.js';
-import * as BufferLayout from 'buffer-layout';
-import { LendingInstruction } from './lending';
-import { calculateUtilizationRatio, LendingReserve } from './reserve';
-import { utils } from '@oyster/common';
-import * as Layout from '../../utils/layout';
-const { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } = utils;
-export enum BorrowAmountType {
- LiquidityBorrowAmount = 0,
- CollateralDepositAmount = 1,
-}
-
-/// Borrow tokens from a reserve by depositing collateral tokens. The number of borrowed tokens
-/// is calculated by market price. The debt obligation is tokenized.
-///
-/// 0. `[writable]` Source collateral token account, minted by deposit reserve collateral mint,
-/// $authority can transfer $collateral_amount
-/// 1. `[writable]` Destination liquidity token account, minted by borrow reserve liquidity mint
-/// 2. `[]` Deposit reserve account.
-/// 3. `[writable]` Deposit reserve collateral supply SPL Token account
-/// 4. `[writable]` Borrow reserve account.
-/// 5. `[writable]` Borrow reserve liquidity supply SPL Token account
-/// 6. `[writable]` Obligation
-/// 7. `[writable]` Obligation token mint
-/// 8. `[writable]` Obligation token output
-/// 8 `[]` Lending market account.
-/// 10 `[]` Derived lending market authority.
-/// 11 `[]` User transfer authority ($authority).
-/// 12 `[]` Dex market
-/// 13 `[]` Dex market order book side
-/// 14 `[]` Temporary memory
-/// 15 `[]` Clock sysvar
-/// 16 '[]` Token program id
-export const borrowInstruction = (
- amount: number | BN,
- amountType: BorrowAmountType,
- from: PublicKey, // Collateral input SPL Token account. $authority can transfer $collateralAmount
- to: PublicKey, // Liquidity output SPL Token account,
- depositReserve: PublicKey,
- depositReserveCollateralSupply: PublicKey,
- ownerFeeReceiver: PublicKey,
-
- borrowReserve: PublicKey,
- borrowReserveLiquiditySupply: PublicKey,
-
- obligation: PublicKey,
- obligationMint: PublicKey,
- obligationTokenOutput: PublicKey,
-
- lendingMarket: PublicKey,
- lendingMarketAuthority: PublicKey,
- transferAuthority: PublicKey,
-
- dexMarket: PublicKey,
- dexOrderBookSide: PublicKey,
-
- memory: PublicKey,
-
- hostFeeReceiver?: PublicKey,
-): TransactionInstruction => {
- const dataLayout = BufferLayout.struct([
- BufferLayout.u8('instruction'),
- Layout.uint64('amount'),
- BufferLayout.u8('amountType'),
- ]);
-
- const data = Buffer.alloc(dataLayout.span);
- dataLayout.encode(
- {
- instruction: LendingInstruction.BorrowLiquidity,
- amount: new BN(amount),
- amountType,
- },
- data,
- );
-
- const keys = [
- { pubkey: from, isSigner: false, isWritable: true },
- { pubkey: to, isSigner: false, isWritable: true },
- { pubkey: depositReserve, isSigner: false, isWritable: false },
- {
- pubkey: depositReserveCollateralSupply,
- isSigner: false,
- isWritable: true,
- },
- { pubkey: ownerFeeReceiver, isSigner: false, isWritable: true },
-
- { pubkey: borrowReserve, isSigner: false, isWritable: true },
- {
- pubkey: borrowReserveLiquiditySupply,
- isSigner: false,
- isWritable: true,
- },
- { pubkey: obligation, isSigner: false, isWritable: true },
- { pubkey: obligationMint, isSigner: false, isWritable: true },
- { pubkey: obligationTokenOutput, isSigner: false, isWritable: true },
-
- { pubkey: lendingMarket, isSigner: false, isWritable: false },
- { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
- { pubkey: transferAuthority, isSigner: true, isWritable: false },
-
- { pubkey: dexMarket, isSigner: false, isWritable: false },
- { pubkey: dexOrderBookSide, isSigner: false, isWritable: false },
- { pubkey: memory, isSigner: false, isWritable: false },
- { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
- { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
- ];
-
- if (hostFeeReceiver) {
- keys.push({ pubkey: hostFeeReceiver, isSigner: false, isWritable: true });
- }
-
- return new TransactionInstruction({
- keys,
- programId: LENDING_PROGRAM_ID,
- data,
- });
-};
-
-// deposit APY utilization currentUtilizationRate * borrowAPY
-
-export const calculateBorrowAPY = (reserve: LendingReserve) => {
- const currentUtilization = calculateUtilizationRatio(reserve);
- const optimalUtilization = reserve.config.optimalUtilizationRate / 100;
-
- let borrowAPY;
- if (optimalUtilization === 1.0 || currentUtilization < optimalUtilization) {
- const normalizedFactor = currentUtilization / optimalUtilization;
- const optimalBorrowRate = reserve.config.optimalBorrowRate / 100;
- const minBorrowRate = reserve.config.minBorrowRate / 100;
- borrowAPY =
- normalizedFactor * (optimalBorrowRate - minBorrowRate) + minBorrowRate;
- } else {
- const normalizedFactor =
- (currentUtilization - optimalUtilization) / (1 - optimalUtilization);
- const optimalBorrowRate = reserve.config.optimalBorrowRate / 100;
- const maxBorrowRate = reserve.config.maxBorrowRate / 100;
- borrowAPY =
- normalizedFactor * (maxBorrowRate - optimalBorrowRate) +
- optimalBorrowRate;
- }
-
- return borrowAPY;
-};
diff --git a/packages/lending/src/models/lending/index.ts b/packages/lending/src/models/lending/index.ts
deleted file mode 100644
index f0c9128a..00000000
--- a/packages/lending/src/models/lending/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export * from './market';
-export * from './reserve';
-export * from './obligation';
-export * from './lending';
-export * from './borrow';
-export * from './deposit';
-export * from './withdraw';
diff --git a/packages/lending/src/models/lending/lending.ts b/packages/lending/src/models/lending/lending.ts
deleted file mode 100644
index e6c4334b..00000000
--- a/packages/lending/src/models/lending/lending.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export enum LendingInstruction {
- InitLendingMarket = 0,
- InitReserve = 1,
- InitObligation = 2,
- DepositReserveLiquidity = 3,
- WithdrawReserveLiquidity = 4,
- BorrowLiquidity = 5,
- RepayOblogationLiquidity = 6,
- LiquidateObligation = 7,
- AccrueReserveInterest = 8,
-}
diff --git a/packages/lending/src/models/lending/obligation.ts b/packages/lending/src/models/lending/obligation.ts
deleted file mode 100644
index 91a9f739..00000000
--- a/packages/lending/src/models/lending/obligation.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import {
- AccountInfo,
- PublicKey,
- SYSVAR_CLOCK_PUBKEY,
- SYSVAR_RENT_PUBKEY,
- TransactionInstruction,
-} from '@solana/web3.js';
-import BN from 'bn.js';
-import * as BufferLayout from 'buffer-layout';
-import { LendingInstruction } from '.';
-import { utils } from '@oyster/common';
-import * as Layout from '../../utils/layout';
-
-const { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } = utils;
-
-export const LendingObligationLayout: typeof BufferLayout.Structure = BufferLayout.struct(
- [
- BufferLayout.u8('version'),
- /// Amount of collateral tokens deposited for this obligation
- Layout.uint64('depositedCollateral'),
- /// Reserve which collateral tokens were deposited into
- Layout.publicKey('collateralReserve'),
- /// Borrow rate used for calculating interest.
- Layout.uint128('cumulativeBorrowRateWad'),
- /// Amount of tokens borrowed for this obligation plus interest
- Layout.uint128('borrowAmountWad'),
- /// Reserve which tokens were borrowed from
- Layout.publicKey('borrowReserve'),
- /// Mint address of the tokens for this obligation
- Layout.publicKey('tokenMint'),
-
- // extra space for future contract changes
- BufferLayout.blob(128, 'padding'),
- ],
-);
-
-export const isLendingObligation = (info: AccountInfo) => {
- return info.data.length === LendingObligationLayout.span;
-};
-
-export interface LendingObligation {
- version: number;
-
- depositedCollateral: BN;
- collateralReserve: PublicKey;
- cumulativeBorrowRateWad: BN; // decimals
- borrowAmountWad: BN; // decimals
- borrowReserve: PublicKey;
- tokenMint: PublicKey;
-}
-
-export const LendingObligationParser = (
- pubKey: PublicKey,
- info: AccountInfo,
-) => {
- const buffer = Buffer.from(info.data);
- const data = LendingObligationLayout.decode(buffer);
-
- const details = {
- pubkey: pubKey,
- account: {
- ...info,
- },
- info: data,
- };
-
- return details;
-};
-
-export const healthFactorToRiskColor = (health: number) => {
- return '';
-};
-
-export const initObligationInstruction = (
- depositReserve: PublicKey,
- borrowReserve: PublicKey,
- obligation: PublicKey,
- obligationMint: PublicKey,
- obligationTokenOutput: PublicKey,
- obligationTokenOwner: PublicKey,
- lendingMarket: PublicKey,
- lendingMarketAuthority: PublicKey,
-): TransactionInstruction => {
- const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]);
-
- const data = Buffer.alloc(dataLayout.span);
- dataLayout.encode(
- {
- instruction: LendingInstruction.InitObligation,
- },
- data,
- );
-
- const keys = [
- { pubkey: depositReserve, isSigner: false, isWritable: false },
- { pubkey: borrowReserve, isSigner: false, isWritable: false },
- { pubkey: obligation, isSigner: false, isWritable: true },
- { pubkey: obligationMint, isSigner: false, isWritable: true },
- { pubkey: obligationTokenOutput, isSigner: false, isWritable: true },
- { pubkey: obligationTokenOwner, isSigner: false, isWritable: false },
-
- { pubkey: lendingMarket, isSigner: false, isWritable: false },
- { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
-
- { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
- { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
- { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
- ];
- return new TransactionInstruction({
- keys,
- programId: LENDING_PROGRAM_ID,
- data,
- });
-};
diff --git a/packages/lending/src/models/lending/repay.ts b/packages/lending/src/models/lending/repay.ts
deleted file mode 100644
index 5447198a..00000000
--- a/packages/lending/src/models/lending/repay.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import {
- PublicKey,
- SYSVAR_CLOCK_PUBKEY,
- TransactionInstruction,
-} from '@solana/web3.js';
-import BN from 'bn.js';
-import { LendingInstruction } from './lending';
-import * as BufferLayout from 'buffer-layout';
-import { utils } from '@oyster/common';
-import * as Layout from '../../utils/layout';
-
-const { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } = utils;
-
-/// Repay loaned tokens to a reserve and receive collateral tokens. The obligation balance
-/// will be recalculated for interest.
-///
-/// 0. `[writable]` Source liquidity token account, minted by repay reserve liquidity mint
-/// $authority can transfer $collateral_amount
-/// 1. `[writable]` Destination collateral token account, minted by withdraw reserve collateral mint
-/// 2. `[writable]` Repay reserve account.
-/// 3. `[writable]` Repay reserve liquidity supply SPL Token account
-/// 4. `[]` Withdraw reserve account.
-/// 5. `[writable]` Withdraw reserve collateral supply SPL Token account
-/// 6. `[writable]` Obligation - initialized
-/// 7. `[writable]` Obligation token mint
-/// 8. `[writable]` Obligation token input, $authority can transfer calculated amount
-/// 9. `[]` Lending market account.
-/// 10 `[]` Derived lending market authority.
-/// 11 `[]` User transfer authority ($authority).
-/// 12 `[]` Clock sysvar
-/// 13 `[]` Token program id
-export const repayInstruction = (
- liquidityAmount: number | BN,
- from: PublicKey, // Liquidity input SPL Token account. $authority can transfer $liquidity_amount
- to: PublicKey, // Collateral output SPL Token account,
- repayReserveAccount: PublicKey,
- repayReserveLiquiditySupply: PublicKey,
- withdrawReserve: PublicKey,
- withdrawReserveCollateralSupply: PublicKey,
- obligation: PublicKey,
- obligationMint: PublicKey,
- obligationInput: PublicKey,
- lendingMarket: PublicKey,
- authority: PublicKey,
- transferAuthority: PublicKey,
-): TransactionInstruction => {
- const dataLayout = BufferLayout.struct([
- BufferLayout.u8('instruction'),
- Layout.uint64('liquidityAmount'),
- ]);
-
- const data = Buffer.alloc(dataLayout.span);
- dataLayout.encode(
- {
- instruction: LendingInstruction.RepayOblogationLiquidity,
- liquidityAmount: new BN(liquidityAmount),
- },
- data,
- );
-
- const keys = [
- { pubkey: from, isSigner: false, isWritable: true },
- { pubkey: to, isSigner: false, isWritable: true },
-
- { pubkey: repayReserveAccount, isSigner: false, isWritable: true },
- { pubkey: repayReserveLiquiditySupply, isSigner: false, isWritable: true },
-
- { pubkey: withdrawReserve, isSigner: false, isWritable: false },
- {
- pubkey: withdrawReserveCollateralSupply,
- isSigner: false,
- isWritable: true,
- },
-
- { pubkey: obligation, isSigner: false, isWritable: true },
- { pubkey: obligationMint, isSigner: false, isWritable: true },
- { pubkey: obligationInput, isSigner: false, isWritable: true },
-
- { pubkey: lendingMarket, isSigner: false, isWritable: false },
- { pubkey: authority, isSigner: false, isWritable: false },
- { pubkey: transferAuthority, isSigner: true, isWritable: false },
-
- { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
- { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
- ];
- return new TransactionInstruction({
- keys,
- programId: LENDING_PROGRAM_ID,
- data,
- });
-};
diff --git a/packages/lending/src/models/lending/reserve.ts b/packages/lending/src/models/lending/reserve.ts
deleted file mode 100644
index 9d26741d..00000000
--- a/packages/lending/src/models/lending/reserve.ts
+++ /dev/null
@@ -1,286 +0,0 @@
-import {
- AccountInfo,
- PublicKey,
- SYSVAR_CLOCK_PUBKEY,
- SYSVAR_RENT_PUBKEY,
- TransactionInstruction,
-} from '@solana/web3.js';
-import BN from 'bn.js';
-import * as BufferLayout from 'buffer-layout';
-import { LendingInstruction } from './lending';
-import { utils } from '@oyster/common';
-import * as Layout from '../../utils/layout';
-
-const { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID, wadToLamports } = utils;
-
-export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct(
- [
- BufferLayout.u8('version'),
- 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(
- [
- /// Optimal utilization rate as a percent
- BufferLayout.u8('optimalUtilizationRate'),
- /// 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'),
- /// Min borrow APY
- BufferLayout.u8('minBorrowRate'),
- /// Optimal (utilization) borrow APY
- BufferLayout.u8('optimalBorrowRate'),
- /// Max borrow APY
- BufferLayout.u8('maxBorrowRate'),
-
- 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'),
- ],
- 'fees',
- ),
- ],
- 'config',
- ),
-
- BufferLayout.struct(
- [
- Layout.uint128('cumulativeBorrowRateWad'),
- Layout.uint128('borrowedLiquidityWad'),
- Layout.uint64('availableLiquidity'),
- Layout.uint64('collateralMintSupply'),
- ],
- 'state',
- ),
-
- // extra space for future contract changes
- BufferLayout.blob(300, 'padding'),
- ],
-);
-
-export const isLendingReserve = (info: AccountInfo) => {
- return info.data.length === LendingReserveLayout.span;
-};
-
-export interface LendingReserve {
- version: number;
-
- lastUpdateSlot: BN;
-
- lendingMarket: PublicKey;
- liquiditySupply: PublicKey;
- liquidityMint: PublicKey;
- collateralMint: PublicKey;
- collateralSupply: PublicKey;
- collateralFeesReceiver: PublicKey;
-
- dexMarketOption: number;
- dexMarket: PublicKey;
-
- config: {
- optimalUtilizationRate: number;
- loanToValueRatio: number;
- liquidationBonus: number;
- liquidationThreshold: number;
- minBorrowRate: number;
- optimalBorrowRate: number;
- maxBorrowRate: number;
-
- fees: {
- borrowFeeWad: BN;
- hostFeePercentage: number;
- };
- };
-
- state: {
- cumulativeBorrowRateWad: BN;
- borrowedLiquidityWad: BN;
-
- availableLiquidity: BN;
- collateralMintSupply: BN;
- };
-}
-
-export const LendingReserveParser = (
- pubKey: PublicKey,
- info: AccountInfo,
-) => {
- const buffer = Buffer.from(info.data);
- const data = LendingReserveLayout.decode(buffer) as LendingReserve;
-
- if (data.lastUpdateSlot.toNumber() === 0) {
- return;
- }
-
- const details = {
- pubkey: pubKey,
- account: {
- ...info,
- },
- info: data,
- };
-
- return details;
-};
-
-export const initReserveInstruction = (
- liquidityAmount: number | BN,
- maxUtilizationRate: number,
-
- from: PublicKey, // Liquidity input SPL Token account. $authority can transfer $liquidity_amount
- to: PublicKey, // Collateral output SPL Token account,
-
- reserveAccount: PublicKey,
- liquidityMint: PublicKey,
- liquiditySupply: PublicKey,
- collateralMint: PublicKey,
- collateralSupply: PublicKey,
- lendingMarket: PublicKey,
- lendingMarketAuthority: PublicKey,
- transferAuthority: PublicKey,
-
- dexMarket: PublicKey, // TODO: optional
-): TransactionInstruction => {
- const dataLayout = BufferLayout.struct([
- BufferLayout.u8('instruction'),
- Layout.uint64('liquidityAmount'),
- BufferLayout.u8('maxUtilizationRate'),
- ]);
-
- const data = Buffer.alloc(dataLayout.span);
- dataLayout.encode(
- {
- instruction: LendingInstruction.InitReserve, // Init reserve instruction
- liquidityAmount: new BN(liquidityAmount),
- maxUtilizationRate: maxUtilizationRate,
- },
- data,
- );
-
- const keys = [
- { pubkey: from, isSigner: false, isWritable: true },
- { pubkey: to, isSigner: false, isWritable: true },
- { pubkey: reserveAccount, isSigner: false, isWritable: true },
- { pubkey: liquidityMint, isSigner: false, isWritable: false },
- { pubkey: liquiditySupply, isSigner: false, isWritable: true },
- { pubkey: collateralMint, isSigner: false, isWritable: true },
- { pubkey: collateralSupply, isSigner: false, isWritable: true },
-
- // NOTE: Why lending market needs to be a signer?
- { pubkey: lendingMarket, isSigner: true, isWritable: true },
- { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false },
- { pubkey: transferAuthority, isSigner: true, isWritable: false },
- { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
- { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
- { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
-
- // optionals
- { pubkey: dexMarket, isSigner: false, isWritable: false },
- ];
- return new TransactionInstruction({
- keys,
- programId: LENDING_PROGRAM_ID,
- data,
- });
-};
-
-export const accrueInterestInstruction = (
- ...reserveAccount: PublicKey[]
-): TransactionInstruction => {
- const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]);
-
- const data = Buffer.alloc(dataLayout.span);
- dataLayout.encode(
- {
- instruction: LendingInstruction.AccrueReserveInterest,
- },
- data,
- );
-
- const keys = [
- { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
- ...reserveAccount.map(reserve => ({
- pubkey: reserve,
- isSigner: false,
- isWritable: true,
- })),
- ];
- return new TransactionInstruction({
- keys,
- programId: LENDING_PROGRAM_ID,
- data,
- });
-};
-
-export const calculateUtilizationRatio = (reserve: LendingReserve) => {
- 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?.state.availableLiquidity.toNumber() || 0;
- const borrowed = wadToLamports(
- reserve?.state.borrowedLiquidityWad,
- ).toNumber();
- const total = available + borrowed;
-
- return total;
-};
-
-export const collateralExchangeRate = (reserve?: LendingReserve) => {
- return (
- (reserve?.state.collateralMintSupply.toNumber() || 1) /
- reserveMarketCap(reserve)
- );
-};
-
-export const collateralToLiquidity = (
- collateralAmount: BN | number,
- reserve?: LendingReserve,
-) => {
- const amount =
- typeof collateralAmount === 'number'
- ? collateralAmount
- : collateralAmount.toNumber();
- return Math.floor(amount / collateralExchangeRate(reserve));
-};
-
-export const liquidityToCollateral = (
- liquidityAmount: BN | number,
- reserve?: LendingReserve,
-) => {
- const amount =
- typeof liquidityAmount === 'number'
- ? liquidityAmount
- : liquidityAmount.toNumber();
- return Math.floor(amount * collateralExchangeRate(reserve));
-};
diff --git a/packages/lending/src/models/lending/withdraw.ts b/packages/lending/src/models/lending/withdraw.ts
deleted file mode 100644
index 8eac7bf6..00000000
--- a/packages/lending/src/models/lending/withdraw.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import {
- PublicKey,
- SYSVAR_CLOCK_PUBKEY,
- TransactionInstruction,
-} from '@solana/web3.js';
-import BN from 'bn.js';
-import * as BufferLayout from 'buffer-layout';
-import { LendingInstruction } from './lending';
-import { utils } from '@oyster/common';
-import * as Layout from '../../utils/layout';
-
-const { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } = utils;
-
-export const withdrawInstruction = (
- collateralAmount: number | BN,
- from: PublicKey, // Collateral input SPL Token account. $authority can transfer $liquidity_amount
- to: PublicKey, // Liquidity output SPL Token account,
- reserveAccount: PublicKey,
- collateralMint: PublicKey,
- reserveSupply: PublicKey,
- lendingMarket: PublicKey,
- authority: PublicKey,
- transferAuthority: PublicKey,
-): TransactionInstruction => {
- const dataLayout = BufferLayout.struct([
- BufferLayout.u8('instruction'),
- Layout.uint64('collateralAmount'),
- ]);
-
- const data = Buffer.alloc(dataLayout.span);
- dataLayout.encode(
- {
- instruction: LendingInstruction.WithdrawReserveLiquidity,
- collateralAmount: new BN(collateralAmount),
- },
- data,
- );
-
- const keys = [
- { pubkey: from, isSigner: false, isWritable: true },
- { pubkey: to, isSigner: false, isWritable: true },
- { pubkey: reserveAccount, isSigner: false, isWritable: true },
- { pubkey: collateralMint, isSigner: false, isWritable: true },
- { pubkey: reserveSupply, isSigner: false, isWritable: true },
- { pubkey: lendingMarket, isSigner: false, isWritable: false },
- { pubkey: authority, isSigner: false, isWritable: false },
- { pubkey: transferAuthority, isSigner: true, isWritable: false },
- { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
- { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
- ];
- return new TransactionInstruction({
- keys,
- programId: LENDING_PROGRAM_ID,
- data,
- });
-};
diff --git a/packages/lending/src/models/pool.ts b/packages/lending/src/models/pool.ts
index db02b5e0..8324e489 100644
--- a/packages/lending/src/models/pool.ts
+++ b/packages/lending/src/models/pool.ts
@@ -1,5 +1,5 @@
-import { PublicKey } from '@solana/web3.js';
import { TokenAccount } from '@oyster/common';
+import { PublicKey } from '@solana/web3.js';
export const DEFAULT_DENOMINATOR = 10_000;
diff --git a/packages/lending/src/models/state/index.ts b/packages/lending/src/models/state/index.ts
new file mode 100644
index 00000000..a49bbc76
--- /dev/null
+++ b/packages/lending/src/models/state/index.ts
@@ -0,0 +1,3 @@
+export * from './lendingMarket';
+export * from './reserve';
+export * from './obligation';
diff --git a/packages/lending/src/models/state/lastUpdate.ts b/packages/lending/src/models/state/lastUpdate.ts
new file mode 100644
index 00000000..b34660a8
--- /dev/null
+++ b/packages/lending/src/models/state/lastUpdate.ts
@@ -0,0 +1,6 @@
+import BN from 'bn.js';
+
+export interface LastUpdate {
+ slot: BN;
+ stale: boolean;
+}
diff --git a/packages/lending/src/models/lending/market.ts b/packages/lending/src/models/state/lendingMarket.ts
similarity index 77%
rename from packages/lending/src/models/lending/market.ts
rename to packages/lending/src/models/state/lendingMarket.ts
index 9b5f1a2c..4b85c84a 100644
--- a/packages/lending/src/models/lending/market.ts
+++ b/packages/lending/src/models/state/lendingMarket.ts
@@ -7,19 +7,17 @@ export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.s
BufferLayout.u8('version'),
BufferLayout.u8('bumpSeed'),
Layout.publicKey('owner'),
- Layout.publicKey('quoteMint'),
+ Layout.publicKey('quoteTokenMint'),
Layout.publicKey('tokenProgramId'),
-
// extra space for future contract changes
- BufferLayout.blob(62, 'padding'),
+ BufferLayout.blob(128, 'padding'),
],
);
export interface LendingMarket {
version: number;
-
isInitialized: boolean;
- quoteMint: PublicKey;
+ quoteTokenMint: PublicKey;
tokenProgramId: PublicKey;
}
@@ -28,22 +26,19 @@ export const isLendingMarket = (info: AccountInfo) => {
};
export const LendingMarketParser = (
- pubKey: PublicKey,
+ pubkey: PublicKey,
info: AccountInfo,
) => {
const buffer = Buffer.from(info.data);
- const data = LendingMarketLayout.decode(buffer);
+ const lendingMarket = LendingMarketLayout.decode(buffer) as LendingMarket;
const details = {
- pubkey: pubKey,
+ pubkey,
account: {
...info,
},
- info: data,
+ info: lendingMarket,
};
return details;
};
-
-// TODO:
-// create instructions for init
diff --git a/packages/lending/src/models/state/obligation.ts b/packages/lending/src/models/state/obligation.ts
new file mode 100644
index 00000000..935e39cf
--- /dev/null
+++ b/packages/lending/src/models/state/obligation.ts
@@ -0,0 +1,81 @@
+import { AccountInfo, PublicKey } from '@solana/web3.js';
+import BN from 'bn.js';
+import * as BufferLayout from 'buffer-layout';
+import * as Layout from '../../utils/layout';
+import { LastUpdate } from './lastUpdate';
+
+// @FIXME: obligation
+export const ObligationLayout: typeof BufferLayout.Structure = BufferLayout.struct(
+ [
+ BufferLayout.u8('version'),
+ /// Amount of collateral tokens deposited for this obligation
+ Layout.uint64('collateral.depositedAmount'),
+ /// Reserve which collateral tokens were deposited into
+ Layout.publicKey('depositReserve'),
+ /// Borrow rate used for calculating interest.
+ Layout.uint128('cumulativeBorrowRateWads'),
+ /// Amount of tokens borrowed for this obligation plus interest
+ Layout.uint128('borrowedAmountWads'),
+ /// Reserve which tokens were borrowed from
+ Layout.publicKey('borrowReserve'),
+
+ // extra space for future contract changes
+ BufferLayout.blob(128, 'padding'),
+ ],
+);
+
+export const isObligation = (info: AccountInfo) => {
+ return info.data.length === ObligationLayout.span;
+};
+
+export interface Obligation {
+ version: number;
+ lastUpdate: LastUpdate;
+ lendingMarket: PublicKey;
+ owner: PublicKey;
+ deposits: ObligationCollateral[];
+ borrows: ObligationLiquidity[];
+ depositedValue: BN; // decimals
+ borrowedValue: BN; // decimals
+ loanToValueRatio: BN; // decimals
+ liquidationThreshold: 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 = (
+ pubkey: PublicKey,
+ info: AccountInfo,
+) => {
+ const buffer = Buffer.from(info.data);
+ const obligation = ObligationLayout.decode(buffer) as Obligation;
+
+ if (obligation.lastUpdate.slot.toNumber() === 0) {
+ return;
+ }
+
+ const details = {
+ pubkey,
+ account: {
+ ...info,
+ },
+ info: obligation,
+ };
+
+ return details;
+};
+
+export const healthFactorToRiskColor = (health: number) => {
+ return '';
+};
diff --git a/packages/lending/src/models/state/reserve.ts b/packages/lending/src/models/state/reserve.ts
new file mode 100644
index 00000000..316482cd
--- /dev/null
+++ b/packages/lending/src/models/state/reserve.ts
@@ -0,0 +1,182 @@
+import { wadToLamports } from '@oyster/common';
+import { AccountInfo, PublicKey } from '@solana/web3.js';
+import BN from 'bn.js';
+import * as BufferLayout from 'buffer-layout';
+import * as Layout from '../../utils/layout';
+import { LastUpdate } from './lastUpdate';
+
+export const ReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct(
+ [
+ BufferLayout.u8('version'),
+
+ BufferLayout.struct(
+ [Layout.uint64('lastUpdateSlot'), BufferLayout.u8('lastUpdateStale')],
+ 'lastUpdate',
+ ),
+
+ Layout.publicKey('lendingMarket'),
+
+ BufferLayout.struct(
+ [
+ Layout.publicKey('liquidityMint'),
+ BufferLayout.u8('liquidityMintDecimals'),
+ Layout.publicKey('liquiditySupply'),
+ Layout.publicKey('liquidityFeeReceiver'),
+ Layout.uint128('cumulativeBorrowRateWads'),
+ Layout.uint128('borrowedAmountWads'),
+ Layout.uint64('availableAmount'),
+ ],
+ 'liquidity',
+ ),
+
+ BufferLayout.struct(
+ [
+ Layout.publicKey('collateralMint'),
+ Layout.uint64('collateralMintAmount'),
+ Layout.publicKey('collateralSupply'),
+ ],
+ 'collateral',
+ ),
+
+ // TODO: replace u32 option with generic equivalent
+ BufferLayout.u32('aggregatorOption'),
+ Layout.publicKey('aggregator'),
+
+ 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',
+ ),
+
+ // extra space for future contract changes
+ BufferLayout.blob(256, 'padding'),
+ ],
+);
+
+export const isReserve = (info: AccountInfo) => {
+ return info.data.length === ReserveLayout.span;
+};
+
+export interface Reserve {
+ version: number;
+ lastUpdate: LastUpdate;
+ lendingMarket: PublicKey;
+ liquidity: ReserveLiquidity;
+ collateral: ReserveCollateral;
+ config: ReserveConfig;
+}
+
+export interface ReserveLiquidity {
+ mint: PublicKey;
+ mintDecimals: number;
+ supply: PublicKey;
+ feeReceiver: PublicKey;
+
+ // @FIXME: aggregator option
+ aggregatorOption: number;
+ aggregator: PublicKey;
+
+ cumulativeBorrowRateWads: BN;
+ marketPrice: BN;
+ availableAmount: BN;
+ borrowedAmountWads: BN;
+}
+
+export interface ReserveCollateral {
+ mint: PublicKey;
+ mintAmount: BN;
+ supply: PublicKey;
+}
+
+export interface ReserveConfig {
+ optimalUtilizationRate: number;
+ loanToValueRatio: number;
+ liquidationBonus: number;
+ liquidationThreshold: number;
+ minBorrowRate: number;
+ optimalBorrowRate: number;
+ maxBorrowRate: number;
+ fees: {
+ borrowFeeWad: BN;
+ hostFeePercentage: number;
+ };
+}
+
+export const ReserveParser = (pubkey: PublicKey, info: AccountInfo) => {
+ const buffer = Buffer.from(info.data);
+ const reserve = ReserveLayout.decode(buffer) as Reserve;
+
+ if (reserve.lastUpdate.slot.toNumber() === 0) {
+ return;
+ }
+
+ const details = {
+ pubkey,
+ account: {
+ ...info,
+ },
+ info: reserve,
+ };
+
+ return details;
+};
+
+export const calculateUtilizationRatio = (reserve: Reserve) => {
+ const totalBorrows = wadToLamports(
+ reserve.liquidity.borrowedAmountWads,
+ ).toNumber();
+ const currentUtilization =
+ totalBorrows /
+ (reserve.liquidity.availableAmount.toNumber() + totalBorrows);
+
+ return currentUtilization;
+};
+
+export const reserveMarketCap = (reserve?: Reserve) => {
+ const available = reserve?.liquidity.availableAmount.toNumber() || 0;
+ const borrowed = wadToLamports(
+ reserve?.liquidity.borrowedAmountWads,
+ ).toNumber();
+ const total = available + borrowed;
+
+ return total;
+};
+
+export const collateralExchangeRate = (reserve?: Reserve) => {
+ return (
+ (reserve?.collateral.mintAmount.toNumber() || 1) / reserveMarketCap(reserve)
+ );
+};
+
+export const collateralToLiquidity = (
+ collateralAmount: BN | number,
+ reserve?: Reserve,
+) => {
+ const amount =
+ typeof collateralAmount === 'number'
+ ? collateralAmount
+ : collateralAmount.toNumber();
+ return Math.floor(amount / collateralExchangeRate(reserve));
+};
+
+export const liquidityToCollateral = (
+ liquidityAmount: BN | number,
+ reserve?: Reserve,
+) => {
+ const amount =
+ typeof liquidityAmount === 'number'
+ ? liquidityAmount
+ : liquidityAmount.toNumber();
+ return Math.floor(amount * collateralExchangeRate(reserve));
+};
diff --git a/packages/lending/src/routes.tsx b/packages/lending/src/routes.tsx
index 2c379f17..7f6bfc17 100644
--- a/packages/lending/src/routes.tsx
+++ b/packages/lending/src/routes.tsx
@@ -1,9 +1,9 @@
-import { HashRouter, Route, Switch } from 'react-router-dom';
-import React from 'react';
import { contexts } from '@oyster/common';
-import { MarketProvider } from './contexts/market';
-import { LendingProvider } from './contexts/lending';
+import React from 'react';
+import { HashRouter, Route, Switch } from 'react-router-dom';
import { AppLayout } from './components/Layout';
+import { LendingProvider } from './contexts/lending';
+import { MarketProvider } from './contexts/market';
import {
BorrowReserveView,
@@ -13,14 +13,15 @@ import {
DepositView,
FaucetView,
HomeView,
+ LiquidateReserveView,
+ LiquidateView,
+ MarginTrading,
RepayReserveView,
ReserveView,
WithdrawView,
- LiquidateView,
- LiquidateReserveView,
- MarginTrading,
} from './views';
import { NewPosition } from './views/margin/newPosition';
+
const { WalletProvider } = contexts.Wallet;
const { ConnectionProvider } = contexts.Connection;
const { AccountsProvider } = contexts.Accounts;
diff --git a/packages/lending/src/utils/pools.ts b/packages/lending/src/utils/pools.ts
index a54564a6..f442cff2 100644
--- a/packages/lending/src/utils/pools.ts
+++ b/packages/lending/src/utils/pools.ts
@@ -1,9 +1,9 @@
+import { contexts, models, programIds } from '@oyster/common';
+import { AccountLayout, MintLayout } from '@solana/spl-token';
import { Connection, PublicKey } from '@solana/web3.js';
import { useEffect, useMemo, useState } from 'react';
-import { MintLayout, AccountLayout } from '@solana/spl-token';
-import { utils, models, contexts } from '@oyster/common';
import { PoolInfo } from '../models';
-const { programIds } = utils;
+
const {
TokenSwapLayout,
TokenSwapLayoutLegacyV0: TokenSwapLayoutV0,
diff --git a/packages/lending/src/utils/utils.ts b/packages/lending/src/utils/utils.ts
index 60509531..b7ec20c8 100644
--- a/packages/lending/src/utils/utils.ts
+++ b/packages/lending/src/utils/utils.ts
@@ -1,4 +1,4 @@
-import { utils, KnownTokenMap } from '@oyster/common';
+import { KnownTokenMap, utils } from '@oyster/common';
import { PoolInfo } from '../models';
export function getPoolName(
diff --git a/packages/lending/src/views/borrow/index.tsx b/packages/lending/src/views/borrow/index.tsx
index 339fe7a7..0000d8be 100644
--- a/packages/lending/src/views/borrow/index.tsx
+++ b/packages/lending/src/views/borrow/index.tsx
@@ -1,9 +1,9 @@
-import { Card } from "antd";
-import React from "react";
-import { LABELS } from "../../constants";
-import { useLendingReserves } from "../../hooks";
-import { BorrowItem } from "./item";
-import "./itemStyle.less";
+import { Card } from 'antd';
+import React from 'react';
+import { LABELS } from '../../constants';
+import { useLendingReserves } from '../../hooks';
+import { BorrowItem } from './item';
+import './itemStyle.less';
export const BorrowView = () => {
const { reserveAccounts } = useLendingReserves();
@@ -17,7 +17,7 @@ export const BorrowView = () => {
{LABELS.TABLE_TITLE_APY}
- {reserveAccounts.map((account) => (
+ {reserveAccounts.map(account => (
{
- const name = useTokenName(props.reserve.liquidityMint);
- const price = useMidPriceInUSD(props.reserve.liquidityMint.toBase58()).price;
+import { useBorrowingPower } from '../../hooks';
+import { calculateBorrowAPY, Reserve } from '../../models';
+
+export const BorrowItem = (props: { reserve: Reserve; address: PublicKey }) => {
+ const name = useTokenName(props.reserve.liquidity.mint);
+ const price = useMidPriceInUSD(props.reserve.liquidity.mint.toBase58()).price;
const { borrowingPower, totalInQuote } = useBorrowingPower(props.address);
@@ -24,7 +25,7 @@ export const BorrowItem = (props: {
-
+
{name}
${formatNumber.format(price)}
diff --git a/packages/lending/src/views/borrowReserve/index.tsx b/packages/lending/src/views/borrowReserve/index.tsx
index 25eebad1..bac5be95 100644
--- a/packages/lending/src/views/borrowReserve/index.tsx
+++ b/packages/lending/src/views/borrowReserve/index.tsx
@@ -1,20 +1,20 @@
-import React from "react";
-import {
- useBorrowingPower,
- useLendingReserve,
- useUserObligations,
-} from "../../hooks";
-import { useParams } from "react-router-dom";
-import "./style.less";
+import { Card, Col, Row, Statistic } from 'antd';
+import React from 'react';
+import { useParams } from 'react-router-dom';
+import { BarChartStatistic } from '../../components/BarChartStatistic';
-import { BorrowInput } from "../../components/BorrowInput";
+import { BorrowInput } from '../../components/BorrowInput';
import {
SideReserveOverview,
SideReserveOverviewMode,
-} from "../../components/SideReserveOverview";
-import { Card, Col, Row, Statistic } from "antd";
-import { BarChartStatistic } from "../../components/BarChartStatistic";
-import { GUTTER, LABELS } from "../../constants";
+} from '../../components/SideReserveOverview';
+import { GUTTER, LABELS } from '../../constants';
+import {
+ useBorrowingPower,
+ useLendingReserve,
+ useUserObligations,
+} from '../../hooks';
+import './style.less';
export const BorrowReserveView = () => {
const { id } = useParams<{ id: string }>();
@@ -55,7 +55,7 @@ export const BorrowReserveView = () => {
@@ -66,10 +66,8 @@ export const BorrowReserveView = () => {
- item.obligation.info.borrowedInQuote / loansValue
- }
- name={(item) => item.obligation.info.repayName}
+ getPct={item => item.obligation.info.borrowedInQuote / loansValue}
+ name={item => item.obligation.info.repayName}
/>
diff --git a/packages/lending/src/views/dashboard/deposit/index.tsx b/packages/lending/src/views/dashboard/deposit/index.tsx
index c2e137d3..57df1917 100644
--- a/packages/lending/src/views/dashboard/deposit/index.tsx
+++ b/packages/lending/src/views/dashboard/deposit/index.tsx
@@ -1,8 +1,8 @@
+import { utils } from '@oyster/common';
import { Card } from 'antd';
import React from 'react';
import { BarChartStatistic } from '../../../components/BarChartStatistic';
import { LABELS } from '../../../constants';
-import { utils } from '@oyster/common';
import { useUserDeposits } from './../../../hooks';
import { DepositItem } from './item';
diff --git a/packages/lending/src/views/dashboard/deposit/item.tsx b/packages/lending/src/views/dashboard/deposit/item.tsx
index 87994a0c..33212212 100644
--- a/packages/lending/src/views/dashboard/deposit/item.tsx
+++ b/packages/lending/src/views/dashboard/deposit/item.tsx
@@ -1,16 +1,19 @@
-import React, { useMemo } from 'react';
-import { hooks, utils, TokenIcon } from '@oyster/common';
-import { UserDeposit } from '../../../hooks';
-import { calculateDepositAPY } from '../../../models/lending';
+import {
+ formatNumber,
+ formatPct,
+ TokenIcon,
+ useTokenName,
+} from '@oyster/common';
import { Button } from 'antd';
+import React, { useMemo } from 'react';
import { Link } from 'react-router-dom';
import { LABELS } from '../../../constants';
-const { useTokenName } = hooks;
-const { formatNumber, formatPct } = utils;
+import { UserDeposit } from '../../../hooks';
+import { calculateDepositAPY } from '../../../models';
export const DepositItem = (props: { userDeposit: UserDeposit }) => {
const { reserve, info } = props.userDeposit;
- const mintAddress = reserve.info.liquidityMint;
+ const mintAddress = reserve.info.liquidity.mint;
const name = useTokenName(mintAddress);
const depositAPY = useMemo(() => calculateDepositAPY(reserve.info), [
diff --git a/packages/lending/src/views/dashboard/index.tsx b/packages/lending/src/views/dashboard/index.tsx
index ada62e7f..0153dd8d 100644
--- a/packages/lending/src/views/dashboard/index.tsx
+++ b/packages/lending/src/views/dashboard/index.tsx
@@ -1,12 +1,13 @@
+import { contexts } from '@oyster/common';
import { Card, Col, Row } from 'antd';
import React from 'react';
+import { NothingBorrowedPanel } from '../../components/NothingBorrowedPanel';
import { GUTTER, LABELS } from '../../constants';
-import { contexts } from '@oyster/common';
import { useUserDeposits, useUserObligations } from './../../hooks';
-import { DashboardObligations } from './obligation';
import { DashboardDeposits } from './deposit';
+import { DashboardObligations } from './obligation';
import './style.less';
-import { NothingBorrowedPanel } from '../../components/NothingBorrowedPanel';
+
const { useWallet } = contexts.Wallet;
export const DashboardView = () => {
diff --git a/packages/lending/src/views/dashboard/obligation/index.tsx b/packages/lending/src/views/dashboard/obligation/index.tsx
index 1784ef79..519fefb2 100644
--- a/packages/lending/src/views/dashboard/obligation/index.tsx
+++ b/packages/lending/src/views/dashboard/obligation/index.tsx
@@ -1,8 +1,8 @@
+import { utils } from '@oyster/common';
import { Card } from 'antd';
import React from 'react';
import { BarChartStatistic } from '../../../components/BarChartStatistic';
import { LABELS } from '../../../constants';
-import { utils } from '@oyster/common';
import { useUserObligations } from './../../../hooks';
import { ObligationItem } from './item';
diff --git a/packages/lending/src/views/dashboard/obligation/item.tsx b/packages/lending/src/views/dashboard/obligation/item.tsx
index 7f5e531f..432a8aae 100644
--- a/packages/lending/src/views/dashboard/obligation/item.tsx
+++ b/packages/lending/src/views/dashboard/obligation/item.tsx
@@ -1,18 +1,24 @@
+import {
+ contexts,
+ formatNumber,
+ formatPct,
+ fromLamports,
+ ParsedAccount,
+ TokenIcon,
+ useTokenName,
+ wadToLamports,
+} from '@oyster/common';
+import { Button } from 'antd';
import React, { useMemo } from 'react';
+import { Link } from 'react-router-dom';
import { EnrichedLendingObligation } from '../../../hooks';
-import { hooks, utils, contexts, ParsedAccount, TokenIcon } from '@oyster/common';
import {
calculateBorrowAPY,
collateralToLiquidity,
healthFactorToRiskColor,
- LendingReserve,
-} from '../../../models/lending';
-
-import { Button } from 'antd';
-import { Link } from 'react-router-dom';
-const { useTokenName } = hooks;
+ Reserve,
+} from '../../../models';
-const { wadToLamports, formatNumber, fromLamports, formatPct } = utils;
const { cache, useMint } = contexts.Accounts;
export const ObligationItem = (props: {
@@ -21,18 +27,18 @@ export const ObligationItem = (props: {
const { obligation } = props;
const borrowReserve = cache.get(
- obligation.info.borrowReserve,
- ) as ParsedAccount;
+ obligation.info.borrows.borrowReserve,
+ ) as ParsedAccount;
- const collateralReserve = cache.get(
- obligation.info.collateralReserve,
- ) as ParsedAccount;
+ const depositReserve = cache.get(
+ obligation.info.deposits.depositReserve,
+ ) as ParsedAccount;
- const liquidityMint = useMint(borrowReserve.info.liquidityMint);
- const collateralMint = useMint(collateralReserve.info.liquidityMint);
+ const liquidityMint = useMint(borrowReserve.info.liquidity.mint);
+ const collateralMint = useMint(depositReserve.info.liquidity.mint);
const borrowAmount = fromLamports(
- wadToLamports(obligation.info.borrowAmountWad),
+ wadToLamports(obligation.info.borrowedAmountWads),
liquidityMint,
);
@@ -41,13 +47,13 @@ export const ObligationItem = (props: {
]);
const collateralLamports = collateralToLiquidity(
- obligation.info.depositedCollateral,
+ obligation.info.deposits.depositedAmount,
borrowReserve.info,
);
const collateral = fromLamports(collateralLamports, collateralMint);
- const borrowName = useTokenName(borrowReserve?.info.liquidityMint);
- const collateralName = useTokenName(collateralReserve?.info.liquidityMint);
+ const borrowName = useTokenName(borrowReserve?.info.liquidity.mint);
+ const collateralName = useTokenName(depositReserve?.info.liquidity.mint);
return (
@@ -57,10 +63,10 @@ export const ObligationItem = (props: {
title={`${collateralName}→${borrowName}`}
>
-
+
diff --git a/packages/lending/src/views/deposit/view/index.tsx b/packages/lending/src/views/deposit/view/index.tsx
index dfb8fc09..d89e3cf7 100644
--- a/packages/lending/src/views/deposit/view/index.tsx
+++ b/packages/lending/src/views/deposit/view/index.tsx
@@ -1,8 +1,8 @@
-import { Card } from "antd";
-import React from "react";
-import { useLendingReserves } from "../../../hooks";
-import { ReserveItem } from "./item";
-import "./itemStyle.less";
+import { Card } from 'antd';
+import React from 'react';
+import { useLendingReserves } from '../../../hooks';
+import { ReserveItem } from './item';
+import './itemStyle.less';
export const DepositView = () => {
const { reserveAccounts } = useLendingReserves();
@@ -16,7 +16,7 @@ export const DepositView = () => {
APY
- {reserveAccounts.map((account) => (
+ {reserveAccounts.map(account => (
{
- const name = useTokenName(props.reserve.liquidityMint);
+ const name = useTokenName(props.reserve.liquidity.mint);
const {
balance: tokenBalance,
balanceInUSD: tokenBalanceInUSD,
- } = useUserBalance(props.reserve.liquidityMint);
+ } = useUserBalance(props.reserve.liquidity.mint);
const {
balance: collateralBalance,
balanceInUSD: collateralBalanceInUSD,
@@ -28,7 +32,7 @@ export const ReserveItem = (props: {
-
+
{name}
diff --git a/packages/lending/src/views/depositReserve/index.tsx b/packages/lending/src/views/depositReserve/index.tsx
index 58e6bdee..5bee0e1e 100644
--- a/packages/lending/src/views/depositReserve/index.tsx
+++ b/packages/lending/src/views/depositReserve/index.tsx
@@ -1,16 +1,16 @@
-import React from "react";
-import { useLendingReserve } from "../../hooks";
-import { useParams } from "react-router-dom";
-import "./style.less";
+import { Col, Row } from 'antd';
+import React from 'react';
+import { useParams } from 'react-router-dom';
+import { DepositInfoLine } from '../../components/DepositInfoLine';
-import { DepositInput } from "../../components/DepositInput";
-import { DepositInfoLine } from "../../components/DepositInfoLine";
+import { DepositInput } from '../../components/DepositInput';
import {
SideReserveOverview,
SideReserveOverviewMode,
-} from "../../components/SideReserveOverview";
-import { Col, Row } from "antd";
-import { GUTTER } from "../../constants";
+} from '../../components/SideReserveOverview';
+import { GUTTER } from '../../constants';
+import { useLendingReserve } from '../../hooks';
+import './style.less';
export const DepositReserveView = () => {
const { id } = useParams<{ id: string }>();
diff --git a/packages/lending/src/views/faucet/index.tsx b/packages/lending/src/views/faucet/index.tsx
index d36a1143..6e05e28c 100644
--- a/packages/lending/src/views/faucet/index.tsx
+++ b/packages/lending/src/views/faucet/index.tsx
@@ -1,11 +1,11 @@
-import React, { useCallback } from 'react';
-import { Card } from 'antd';
+import { ConnectButton, contexts, notify } from '@oyster/common';
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
+import { Card } from 'antd';
+import React, { useCallback } from 'react';
import { LABELS } from '../../constants';
-import { contexts, utils, ConnectButton } from '@oyster/common';
+
const { useConnection } = contexts.Connection;
const { useWallet } = contexts.Wallet;
-const { notify } = utils;
export const FaucetView = () => {
const connection = useConnection();
diff --git a/packages/lending/src/views/home/index.tsx b/packages/lending/src/views/home/index.tsx
index 42f4b43a..185ab27f 100644
--- a/packages/lending/src/views/home/index.tsx
+++ b/packages/lending/src/views/home/index.tsx
@@ -1,16 +1,21 @@
+import {
+ contexts,
+ fromLamports,
+ getTokenName,
+ ParsedAccount,
+ wadToLamports,
+} from '@oyster/common';
import { MintInfo } from '@solana/spl-token';
import { Card, Col, Row, Statistic } from 'antd';
import React, { useEffect, useState } from 'react';
import { GUTTER, LABELS } from '../../constants';
-import { contexts, ParsedAccount, utils } from '@oyster/common';
import { useMarkets } from '../../contexts/market';
import { useLendingReserves } from '../../hooks';
import { reserveMarketCap, Totals } from '../../models';
-
-import { LendingReserveItem } from './item';
import { BarChartStatistic } from './../../components/BarChartStatistic';
+import { LendingReserveItem } from './item';
import './itemStyle.less';
-const { fromLamports, getTokenName, wadToLamports } = utils;
+
const { cache } = contexts.Accounts;
const { useConnectionConfig } = contexts.Connection;
@@ -39,7 +44,7 @@ export const HomeView = () => {
const localCache = cache;
const liquidityMint = localCache.get(
- item.info.liquidityMint.toBase58(),
+ item.info.liquidity.mint.toBase58(),
) as ParsedAccount
;
if (!liquidityMint) {
@@ -54,10 +59,10 @@ export const HomeView = () => {
fromLamports(marketCapLamports, liquidityMint?.info) * price,
borrowed:
fromLamports(
- wadToLamports(item.info?.state.borrowedLiquidityWad).toNumber(),
+ wadToLamports(item.info?.liquidity.borrowedAmountWads).toNumber(),
liquidityMint.info,
) * price,
- name: getTokenName(tokenMap, item.info.liquidityMint.toBase58()),
+ name: getTokenName(tokenMap, item.info.liquidity.mint.toBase58()),
};
newTotals.items.push(leaf);
diff --git a/packages/lending/src/views/home/item.tsx b/packages/lending/src/views/home/item.tsx
index 54149134..bd19d08c 100644
--- a/packages/lending/src/views/home/item.tsx
+++ b/packages/lending/src/views/home/item.tsx
@@ -1,36 +1,42 @@
+import {
+ contexts,
+ formatNumber,
+ formatPct,
+ fromLamports,
+ TokenIcon,
+ useTokenName,
+ wadToLamports,
+} from '@oyster/common';
+import { PublicKey } from '@solana/web3.js';
import React, { useMemo } from 'react';
+import { Link } from 'react-router-dom';
import {
calculateBorrowAPY,
calculateDepositAPY,
- LendingReserve,
-} from '../../models/lending';
+ Reserve,
+ TotalItem,
+} from '../../models';
-import { Link } from 'react-router-dom';
-import { PublicKey } from '@solana/web3.js';
-import { TotalItem } from '../../models';
-import { contexts, hooks, utils, TokenIcon } from '@oyster/common';
-const { wadToLamports, formatNumber, fromLamports, formatPct } = utils;
const { useMint } = contexts.Accounts;
-const { useTokenName } = hooks;
export const LendingReserveItem = (props: {
- reserve: LendingReserve;
+ reserve: Reserve;
address: PublicKey;
item?: TotalItem;
}) => {
- const name = useTokenName(props.reserve.liquidityMint);
+ const name = useTokenName(props.reserve.liquidity.mint);
- const liquidityMint = useMint(props.reserve.liquidityMint);
+ const liquidityMint = useMint(props.reserve.liquidity.mint);
- const availableLiquidity = fromLamports(
- props.reserve.state.availableLiquidity,
+ const availableAmount = fromLamports(
+ props.reserve.liquidity.availableAmount,
liquidityMint,
);
const totalBorrows = useMemo(
() =>
fromLamports(
- wadToLamports(props.reserve.state.borrowedLiquidityWad),
+ wadToLamports(props.reserve.liquidity.borrowedAmountWads),
liquidityMint,
),
[props.reserve, liquidityMint],
@@ -44,13 +50,13 @@ export const LendingReserveItem = (props: {
props.reserve,
]);
- const marketSize = availableLiquidity + totalBorrows;
+ const marketSize = availableAmount + totalBorrows;
return (
-
+
{name}
diff --git a/packages/lending/src/views/liquidate/index.tsx b/packages/lending/src/views/liquidate/index.tsx
index 04d03bd6..a8b80d83 100644
--- a/packages/lending/src/views/liquidate/index.tsx
+++ b/packages/lending/src/views/liquidate/index.tsx
@@ -1,22 +1,22 @@
-import React, { useMemo } from "react";
-import { GUTTER, LABELS } from "../../constants";
-import { LiquidateItem } from "./item";
-import { useEnrichedLendingObligations } from "../../hooks";
-import "./style.less";
-import { Card, Col, Row, Statistic, Typography } from "antd";
-import { BarChartStatistic } from "../../components/BarChartStatistic";
+import { Card, Col, Row, Statistic, Typography } from 'antd';
+import React, { useMemo } from 'react';
+import { BarChartStatistic } from '../../components/BarChartStatistic';
+import { GUTTER, LABELS } from '../../constants';
+import { useEnrichedLendingObligations } from '../../hooks';
+import { LiquidateItem } from './item';
+import './style.less';
export const LiquidateView = () => {
const { obligations } = useEnrichedLendingObligations();
const atRisk = useMemo(
- () => obligations.filter((item) => item.info.health < 1.0),
- [obligations]
+ () => obligations.filter(item => item.info.health < 1.0),
+ [obligations],
);
const valueAtRisk = useMemo(
() => atRisk.reduce((acc, item) => acc + item.info.collateralInQuote, 0),
- [atRisk]
+ [atRisk],
);
const loansAtRiskCount = useMemo(() => atRisk.length, [atRisk]);
const pctAtRisk = useMemo(() => atRisk.length / obligations.length, [
@@ -28,7 +28,7 @@ export const LiquidateView = () => {
return atRisk.reduce((acc, item) => {
acc.set(
item.info.repayName,
- (acc.get(item.info.collateralName) || 0) + item.info.collateralInQuote
+ (acc.get(item.info.collateralName) || 0) + item.info.collateralInQuote,
);
return acc;
}, new Map
());
@@ -56,7 +56,7 @@ export const LiquidateView = () => {
title="Value at risk"
value={valueAtRisk}
precision={2}
- valueStyle={{ color: "#3fBB00" }}
+ valueStyle={{ color: '#3fBB00' }}
prefix="$"
/>
@@ -84,8 +84,8 @@ export const LiquidateView = () => {
item}
- getPct={(item) => (groupedLoans.get(item) || 0) / valueAtRisk}
+ name={item => item}
+ getPct={item => (groupedLoans.get(item) || 0) / valueAtRisk}
items={keys}
/>
@@ -103,7 +103,7 @@ export const LiquidateView = () => {
{LABELS.TABLE_TITLE_HEALTH}
{LABELS.TABLE_TITLE_ACTION}
- {atRisk.map((item) => (
+ {atRisk.map(item => (
{
let obligation = props.item.info;
const borrowReserve = cache.get(
- obligation.borrowReserve,
- ) as ParsedAccount;
+ obligation.borrows.borrowReserve,
+ ) as ParsedAccount;
- const collateralReserve = cache.get(
- obligation.collateralReserve,
- ) as ParsedAccount;
+ const depositReserve = cache.get(
+ obligation.deposits.depositReserve,
+ ) as ParsedAccount;
- const liquidityMint = useMint(borrowReserve.info.liquidityMint);
- const collateralMint = useMint(collateralReserve.info.liquidityMint);
+ const liquidityMint = useMint(borrowReserve.info.liquidity.mint);
+ const collateralMint = useMint(depositReserve.info.liquidity.mint);
const borrowAmount = fromLamports(
- wadToLamports(obligation.borrowAmountWad),
+ wadToLamports(obligation.deposits.borrowedAmountWads),
liquidityMint,
);
@@ -40,13 +45,13 @@ export const LiquidateItem = (props: { item: EnrichedLendingObligation }) => {
]);
const collateralLamports = collateralToLiquidity(
- obligation.depositedCollateral,
+ obligation.deposits.depositedAmount,
borrowReserve.info,
);
const collateral = fromLamports(collateralLamports, collateralMint);
- const borrowName = useTokenName(borrowReserve?.info.liquidityMint);
- const collateralName = useTokenName(collateralReserve?.info.liquidityMint);
+ const borrowName = useTokenName(borrowReserve?.info.liquidity.mint);
+ const collateralName = useTokenName(depositReserve?.info.liquidity.mint);
return (
@@ -54,10 +59,10 @@ export const LiquidateItem = (props: { item: EnrichedLendingObligation }) => {
-
+
{collateralName}→{borrowName}
diff --git a/packages/lending/src/views/liquidateReserve/index.tsx b/packages/lending/src/views/liquidateReserve/index.tsx
index ade0c704..15b6150e 100644
--- a/packages/lending/src/views/liquidateReserve/index.tsx
+++ b/packages/lending/src/views/liquidateReserve/index.tsx
@@ -1,18 +1,18 @@
-import React from "react";
-import { useParams } from "react-router-dom";
-import { useEnrichedLendingObligation, useLendingReserve } from "../../hooks";
+import { Col, Row } from 'antd';
+import React from 'react';
+import { useParams } from 'react-router-dom';
+
+import { LiquidateInput } from '../../components/LiquidateInput';
+
+import { LoanInfoLine } from '../../components/LoanInfoLine';
import {
SideReserveOverview,
SideReserveOverviewMode,
-} from "../../components/SideReserveOverview";
-
-import { LoanInfoLine } from "../../components/LoanInfoLine";
-
-import { LiquidateInput } from "../../components/LiquidateInput";
+} from '../../components/SideReserveOverview';
+import { GUTTER } from '../../constants';
+import { useEnrichedLendingObligation, useLendingReserve } from '../../hooks';
-import "./style.less";
-import { Col, Row } from "antd";
-import { GUTTER } from "../../constants";
+import './style.less';
export const LiquidateReserveView = () => {
const { id } = useParams<{ id: string }>();
@@ -20,7 +20,7 @@ export const LiquidateReserveView = () => {
const obligation = useEnrichedLendingObligation(id);
const repayReserve = useLendingReserve(obligation?.info.borrowReserve);
- const withdrawReserve = useLendingReserve(obligation?.info.collateralReserve);
+ const withdrawReserve = useLendingReserve(obligation?.info.depositReserve);
if (!obligation || !repayReserve) {
return null;
diff --git a/packages/lending/src/views/margin/index.tsx b/packages/lending/src/views/margin/index.tsx
index 1596d563..69fea976 100644
--- a/packages/lending/src/views/margin/index.tsx
+++ b/packages/lending/src/views/margin/index.tsx
@@ -1,9 +1,9 @@
-import React from "react";
-import { LABELS } from "../../constants";
-import "./itemStyle.less";
-import { Card } from "antd";
-import { useLendingReserves } from "../../hooks/useLendingReserves";
-import { MarginTradeItem } from "./item";
+import { Card } from 'antd';
+import React from 'react';
+import { LABELS } from '../../constants';
+import { useLendingReserves } from '../../hooks/useLendingReserves';
+import { MarginTradeItem } from './item';
+import './itemStyle.less';
export const MarginTrading = () => {
const { reserveAccounts } = useLendingReserves();
@@ -17,7 +17,7 @@ export const MarginTrading = () => {
{LABELS.TABLE_TITLE_APY}
- {reserveAccounts.map((account) => (
+ {reserveAccounts.map(account => (
))}
diff --git a/packages/lending/src/views/margin/item.tsx b/packages/lending/src/views/margin/item.tsx
index 0338cc99..04fbf253 100644
--- a/packages/lending/src/views/margin/item.tsx
+++ b/packages/lending/src/views/margin/item.tsx
@@ -1,21 +1,24 @@
-import React from 'react';
-import { hooks, utils, TokenIcon } from '@oyster/common';
-import { useBorrowingPower } from '../../hooks';
-import { calculateBorrowAPY, LendingReserve } from '../../models/lending';
+import {
+ formatNumber,
+ formatPct,
+ TokenIcon,
+ useTokenName,
+} from '@oyster/common';
+import { PublicKey } from '@solana/web3.js';
import { Button } from 'antd';
+import React from 'react';
import { Link } from 'react-router-dom';
-import { PublicKey } from '@solana/web3.js';
import { LABELS } from '../../constants';
import { useMidPriceInUSD } from '../../contexts/market';
-const { formatNumber, formatPct } = utils;
-const { useTokenName } = hooks;
+import { useBorrowingPower } from '../../hooks';
+import { calculateBorrowAPY, Reserve } from '../../models';
export const MarginTradeItem = (props: {
- reserve: LendingReserve;
+ reserve: Reserve;
address: PublicKey;
}) => {
- const name = useTokenName(props.reserve.liquidityMint);
- const price = useMidPriceInUSD(props.reserve.liquidityMint.toBase58()).price;
+ const name = useTokenName(props.reserve.liquidity.mint);
+ const price = useMidPriceInUSD(props.reserve.liquidity.mint.toBase58()).price;
const apr = calculateBorrowAPY(props.reserve);
@@ -30,7 +33,7 @@ export const MarginTradeItem = (props: {
-
+
{name}
${formatNumber.format(price)}
diff --git a/packages/lending/src/views/margin/newPosition/Breakdown.tsx b/packages/lending/src/views/margin/newPosition/Breakdown.tsx
index 03e02bb5..41aea186 100644
--- a/packages/lending/src/views/margin/newPosition/Breakdown.tsx
+++ b/packages/lending/src/views/margin/newPosition/Breakdown.tsx
@@ -1,10 +1,10 @@
-import { Progress, Slider, Card, Statistic } from 'antd';
+import { ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
+import { useConnectionConfig } from '@oyster/common';
+import { Card, Progress, Slider, Statistic } from 'antd';
import React, { useState } from 'react';
-import { Position } from './interfaces';
-import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons';
import GainsChart from './GainsChart';
+import { Position } from './interfaces';
import { usePoolAndTradeInfoFrom } from './utils';
-import { useConnectionConfig } from '@oyster/common';
export default function Breakdown({ item }: { item: Position }) {
const { tokens } = useConnectionConfig();
@@ -22,11 +22,10 @@ export default function Breakdown({ item }: { item: Position }) {
const gains = 'green';
const losses = 'red';
const token = tokens.find(
- t => t.address === item.asset.type?.info?.liquidityMint?.toBase58(),
+ t => t.address === item.asset.type?.info?.liquidity.mint?.toBase58(),
);
const collateralToken = tokens.find(
- t =>
- t.address === item.collateral.type?.info?.liquidityMint?.toBase58(),
+ t => t.address === item.collateral.type?.info?.liquidity.mint?.toBase58(),
);
const [myGain, setMyGain] = useState
(10);
diff --git a/packages/lending/src/views/margin/newPosition/GainsChart.tsx b/packages/lending/src/views/margin/newPosition/GainsChart.tsx
index b1571bf6..fb7bd676 100644
--- a/packages/lending/src/views/margin/newPosition/GainsChart.tsx
+++ b/packages/lending/src/views/margin/newPosition/GainsChart.tsx
@@ -1,6 +1,6 @@
-import React, { useEffect, useRef } from "react";
-import Chart, { ChartPluginsOptions } from "chart.js";
-import { Position } from "./interfaces";
+import Chart, { ChartPluginsOptions } from 'chart.js';
+import React, { useEffect, useRef } from 'react';
+import { Position } from './interfaces';
// Special thanks to
// https://github.com/bZxNetwork/fulcrum_ui/blob/development/packages/fulcrum-website/assets/js/trading.js
diff --git a/packages/lending/src/views/margin/newPosition/NewPositionForm.tsx b/packages/lending/src/views/margin/newPosition/NewPositionForm.tsx
index 0af1532f..40249f0f 100644
--- a/packages/lending/src/views/margin/newPosition/NewPositionForm.tsx
+++ b/packages/lending/src/views/margin/newPosition/NewPositionForm.tsx
@@ -1,24 +1,21 @@
+import { ArrowDownOutlined } from '@ant-design/icons';
+import { components, contexts, ParsedAccount } from '@oyster/common';
import { Button, Card } from 'antd';
import React, { useState } from 'react';
+import CollateralInput from '../../../components/CollateralInput';
import { LABELS } from '../../../constants';
-import { contexts, ParsedAccount, components } from '@oyster/common';
-import {
- LendingReserve,
- LendingReserveParser,
-} from '../../../models/lending/reserve';
+import { UserDeposit } from '../../../hooks';
+import { Reserve, ReserveParser } from '../../../models';
import { Position } from './interfaces';
import { useLeverage } from './leverage';
-import CollateralInput from '../../../components/CollateralInput';
import { usePoolAndTradeInfoFrom } from './utils';
-import { UserDeposit } from '../../../hooks';
-import { ArrowDownOutlined } from '@ant-design/icons';
const { ActionConfirmation } = components;
const { cache } = contexts.Accounts;
const { useWallet } = contexts.Wallet;
interface NewPositionFormProps {
- lendingReserve: ParsedAccount;
+ lendingReserve: ParsedAccount;
newPosition: Position;
setNewPosition: (pos: Position) => void;
}
@@ -144,9 +141,9 @@ export default function NewPositionForm({
onCollateralReserve={key => {
const id: string =
cache
- .byParser(LendingReserveParser)
+ .byParser(ReserveParser)
.find(acc => acc === key) || '';
- const parser = cache.get(id) as ParsedAccount;
+ const parser = cache.get(id) as ParsedAccount;
const newPos = {
...newPosition,
collateral: {
diff --git a/packages/lending/src/views/margin/newPosition/PoolHealth.tsx b/packages/lending/src/views/margin/newPosition/PoolHealth.tsx
index 72bddaf0..fa7c6035 100644
--- a/packages/lending/src/views/margin/newPosition/PoolHealth.tsx
+++ b/packages/lending/src/views/margin/newPosition/PoolHealth.tsx
@@ -1,9 +1,9 @@
-import Card from "antd/lib/card";
-import React from "react";
-import { PoolPrice } from "../../../components/PoolPrice";
-import { SupplyOverview } from "../../../components/SupplyOverview";
-import { Position } from "./interfaces";
-import { usePoolAndTradeInfoFrom } from "./utils";
+import Card from 'antd/lib/card';
+import React from 'react';
+import { PoolPrice } from '../../../components/PoolPrice';
+import { SupplyOverview } from '../../../components/SupplyOverview';
+import { Position } from './interfaces';
+import { usePoolAndTradeInfoFrom } from './utils';
export default function PoolHealth({ newPosition }: { newPosition: Position }) {
const { pool } = usePoolAndTradeInfoFrom(newPosition);
diff --git a/packages/lending/src/views/margin/newPosition/index.tsx b/packages/lending/src/views/margin/newPosition/index.tsx
index 2acd889e..8b02fb11 100644
--- a/packages/lending/src/views/margin/newPosition/index.tsx
+++ b/packages/lending/src/views/margin/newPosition/index.tsx
@@ -1,12 +1,12 @@
-import React, { useState } from "react";
-import { useLendingReserve } from "../../../hooks";
-import { useParams } from "react-router-dom";
-import "./style.less";
+import React, { useState } from 'react';
+import { useParams } from 'react-router-dom';
+import { useLendingReserve } from '../../../hooks';
+import Breakdown from './Breakdown';
+import { Position } from './interfaces';
-import NewPositionForm from "./NewPositionForm";
-import { Position } from "./interfaces";
-import Breakdown from "./Breakdown";
-import PoolHealth from "./PoolHealth";
+import NewPositionForm from './NewPositionForm';
+import PoolHealth from './PoolHealth';
+import './style.less';
export const NewPosition = () => {
const { id } = useParams<{ id: string }>();
diff --git a/packages/lending/src/views/margin/newPosition/interfaces.tsx b/packages/lending/src/views/margin/newPosition/interfaces.tsx
index 4bc0eb66..233aba62 100644
--- a/packages/lending/src/views/margin/newPosition/interfaces.tsx
+++ b/packages/lending/src/views/margin/newPosition/interfaces.tsx
@@ -1,5 +1,5 @@
import { ParsedAccount } from '@oyster/common';
-import { LendingReserve } from '../../../models/lending/reserve';
+import { Reserve } from '../../../models';
export interface Token {
mintAddress: string;
@@ -11,11 +11,11 @@ export interface Position {
id?: number | null;
leverage: number;
collateral: {
- type?: ParsedAccount;
+ type?: ParsedAccount;
value?: number | null;
};
asset: {
- type?: ParsedAccount;
+ type?: ParsedAccount;
value?: number | null;
};
error?: string;
diff --git a/packages/lending/src/views/margin/newPosition/utils.ts b/packages/lending/src/views/margin/newPosition/utils.ts
index 8570461c..50ebcd35 100644
--- a/packages/lending/src/views/margin/newPosition/utils.ts
+++ b/packages/lending/src/views/margin/newPosition/utils.ts
@@ -1,7 +1,7 @@
import { ParsedAccount } from '@oyster/common';
import { useEnrichedPools } from '../../../contexts/market';
import { UserDeposit, useUserDeposits } from '../../../hooks';
-import { LendingReserve, PoolInfo } from '../../../models';
+import { PoolInfo, Reserve } from '../../../models';
import { usePoolForBasket } from '../../../utils/pools';
import { Position } from './interfaces';
@@ -10,8 +10,8 @@ export function usePoolAndTradeInfoFrom(
): {
enrichedPools: any[];
collateralDeposit: UserDeposit | undefined;
- collType: ParsedAccount | undefined;
- desiredType: ParsedAccount | undefined;
+ collType: ParsedAccount | undefined;
+ desiredType: ParsedAccount | undefined;
collValue: number;
desiredValue: number;
leverage: number;
@@ -23,15 +23,15 @@ export function usePoolAndTradeInfoFrom(
const desiredValue = newPosition.asset.value || 0;
const pool = usePoolForBasket([
- collType?.info?.liquidityMint?.toBase58(),
- desiredType?.info?.liquidityMint?.toBase58(),
+ collType?.info?.liquidity.mint?.toBase58(),
+ desiredType?.info?.liquidity.mint?.toBase58(),
]);
const userDeposits = useUserDeposits();
const collateralDeposit = userDeposits.userDeposits.find(
u =>
- u.reserve.info.liquidityMint.toBase58() ===
- collType?.info?.liquidityMint?.toBase58(),
+ u.reserve.info.liquidity.mint.toBase58() ===
+ collType?.info?.liquidity.mint?.toBase58(),
);
const enrichedPools = useEnrichedPools(pool ? [pool] : []);
diff --git a/packages/lending/src/views/repayReserve/index.tsx b/packages/lending/src/views/repayReserve/index.tsx
index b16c9f0d..1060e3e7 100644
--- a/packages/lending/src/views/repayReserve/index.tsx
+++ b/packages/lending/src/views/repayReserve/index.tsx
@@ -1,22 +1,22 @@
-import React from "react";
+import { Card, Col, Row, Statistic } from 'antd';
+import React from 'react';
+import { useParams } from 'react-router-dom';
+import { BarChartStatistic } from '../../components/BarChartStatistic';
+
+import { RepayInput } from '../../components/RepayInput';
+import {
+ SideReserveOverview,
+ SideReserveOverviewMode,
+} from '../../components/SideReserveOverview';
+import { GUTTER, LABELS } from '../../constants';
import {
useBorrowingPower,
useEnrichedLendingObligation,
useLendingReserve,
useUserObligations,
-} from "../../hooks";
-import { useParams } from "react-router-dom";
-
-import { RepayInput } from "../../components/RepayInput";
-import {
- SideReserveOverview,
- SideReserveOverviewMode,
-} from "../../components/SideReserveOverview";
+} from '../../hooks';
-import "./style.less";
-import { Card, Col, Row, Statistic } from "antd";
-import { BarChartStatistic } from "../../components/BarChartStatistic";
-import { GUTTER, LABELS } from "../../constants";
+import './style.less';
export const RepayReserveView = () => {
const { reserve: reserveId, obligation: obligationId } = useParams<{
@@ -29,7 +29,7 @@ export const RepayReserveView = () => {
const lendingReserve = useLendingReserve(id);
const repayReserve = useLendingReserve(
- obligationId ? lendingObligation?.info.collateralReserve : reserveId
+ obligationId ? lendingObligation?.info.depositReserve : reserveId,
);
const { userObligations, totalInQuote: loansValue } = useUserObligations();
@@ -69,7 +69,7 @@ export const RepayReserveView = () => {
@@ -80,10 +80,8 @@ export const RepayReserveView = () => {
- item.obligation.info.borrowedInQuote / loansValue
- }
- name={(item) => item.obligation.info.repayName}
+ getPct={item => item.obligation.info.borrowedInQuote / loansValue}
+ name={item => item.obligation.info.repayName}
/>
@@ -93,7 +91,7 @@ export const RepayReserveView = () => {
diff --git a/packages/lending/src/views/reserve/index.tsx b/packages/lending/src/views/reserve/index.tsx
index d32ac85c..be8cccb0 100644
--- a/packages/lending/src/views/reserve/index.tsx
+++ b/packages/lending/src/views/reserve/index.tsx
@@ -1,12 +1,12 @@
-import React from "react";
-import { useLendingReserve } from "../../hooks";
-import { useParams } from "react-router-dom";
-import "./style.less";
+import { Col, Row } from 'antd';
+import React from 'react';
+import { useParams } from 'react-router-dom';
+import { ReserveStatus } from '../../components/ReserveStatus';
-import { UserLendingCard } from "../../components/UserLendingCard";
-import { ReserveStatus } from "../../components/ReserveStatus";
-import { Col, Row } from "antd";
-import { GUTTER } from "../../constants";
+import { UserLendingCard } from '../../components/UserLendingCard';
+import { GUTTER } from '../../constants';
+import { useLendingReserve } from '../../hooks';
+import './style.less';
export const ReserveView = () => {
const { id } = useParams<{ id: string }>();
diff --git a/packages/lending/src/views/withdraw/index.tsx b/packages/lending/src/views/withdraw/index.tsx
index 86279037..656eb462 100644
--- a/packages/lending/src/views/withdraw/index.tsx
+++ b/packages/lending/src/views/withdraw/index.tsx
@@ -1,14 +1,14 @@
-import React from "react";
-import { useLendingReserve } from "../../hooks";
-import { useParams } from "react-router-dom";
-import "./style.less";
-
-import { WithdrawInput } from "../../components/WithdrawInput";
-import { DepositInfoLine } from "../../components/DepositInfoLine";
+import React from 'react';
+import { useParams } from 'react-router-dom';
+import { DepositInfoLine } from '../../components/DepositInfoLine';
import {
SideReserveOverview,
SideReserveOverviewMode,
-} from "../../components/SideReserveOverview";
+} from '../../components/SideReserveOverview';
+
+import { WithdrawInput } from '../../components/WithdrawInput';
+import { useLendingReserve } from '../../hooks';
+import './style.less';
export const WithdrawView = () => {
const { id } = useParams<{ id: string }>();