diff --git a/packages/lending/src/App.tsx b/packages/lending/src/App.tsx index 21da6499..d2220c74 100644 --- a/packages/lending/src/App.tsx +++ b/packages/lending/src/App.tsx @@ -1,6 +1,6 @@ -import React from "react"; -import "./App.less"; -import { Routes } from "./routes"; +import React from 'react'; +import './App.less'; +import { Routes } from './routes'; function App() { return ; diff --git a/packages/lending/src/actions/borrow.tsx b/packages/lending/src/actions/borrowObligationLiquidity.tsx similarity index 56% rename from packages/lending/src/actions/borrow.tsx rename to packages/lending/src/actions/borrowObligationLiquidity.tsx index a37cf2f6..81ec1924 100644 --- a/packages/lending/src/actions/borrow.tsx +++ b/packages/lending/src/actions/borrowObligationLiquidity.tsx @@ -1,37 +1,33 @@ import { - Account, - Connection, - PublicKey, - TransactionInstruction, -} from '@solana/web3.js'; -import { - contexts, - utils, actions, + contexts, + LEND_HOST_FEE_ADDRESS, + LENDING_PROGRAM_ID, models, - TokenAccount, + notify, ParsedAccount, + TokenAccount, + toLamports, } from '@oyster/common'; - +import { AccountLayout, MintInfo } from '@solana/spl-token'; import { - accrueInterestInstruction, - LendingReserve, -} from './../models/lending/reserve'; -import { AccountLayout, MintInfo, MintLayout } from '@solana/spl-token'; - -import { createUninitializedObligation } from './obligation'; - + Account, + Connection, + PublicKey, + TransactionInstruction, +} from '@solana/web3.js'; import { - LendingObligationLayout, - borrowInstruction, - LendingMarket, BorrowAmountType, - LendingObligation, + borrowObligationLiquidityInstruction, initObligationInstruction, + Obligation, + ObligationLayout, + refreshReserveInstruction, + Reserve, } from '../models'; +import { createObligation } from './createObligation'; const { approve } = models; -const { toLamports, LENDING_PROGRAM_ID, LEND_HOST_FEE_ADDRESS, notify } = utils; const { cache, MintParser } = contexts.Accounts; const { sendTransaction } = contexts.Connection; const { @@ -42,19 +38,15 @@ const { findOrCreateAccountByMint, } = actions; -export const borrow = async ( +// @FIXME +export const borrowObligationLiquidity = async ( connection: Connection, wallet: any, - from: TokenAccount, amount: number, - amountType: BorrowAmountType, - - borrowReserve: ParsedAccount, - - depositReserve: ParsedAccount, - - existingObligation?: ParsedAccount, + borrowReserve: ParsedAccount, + depositReserve: ParsedAccount, + existingObligation: ParsedAccount, obligationAccount?: PublicKey, ) => { @@ -69,7 +61,7 @@ export const borrow = async ( let cleanupInstructions: TransactionInstruction[] = []; let finalCleanupInstructions: TransactionInstruction[] = []; - const [authority] = await PublicKey.findProgramAddress( + const [lendingMarketAuthority] = await PublicKey.findProgramAddress( [depositReserve.info.lendingMarket.toBuffer()], LENDING_PROGRAM_ID, ); @@ -80,44 +72,21 @@ export const borrow = async ( const obligation = existingObligation ? existingObligation.pubkey - : createUninitializedObligation( + : createObligation( instructions, wallet.publicKey, await connection.getMinimumBalanceForRentExemption( - LendingObligationLayout.span, + ObligationLayout.span, ), signers, ); - const obligationMint = existingObligation - ? existingObligation.info.tokenMint - : createUninitializedMint( - instructions, - wallet.publicKey, - await connection.getMinimumBalanceForRentExemption(MintLayout.span), - signers, - ); - - const obligationTokenOutput = obligationAccount - ? obligationAccount - : createUninitializedAccount( - instructions, - wallet.publicKey, - accountRentExempt, - signers, - ); - if (!obligationAccount) { instructions.push( initObligationInstruction( - depositReserve.pubkey, - borrowReserve.pubkey, obligation, - obligationMint, - obligationTokenOutput, - wallet.publicKey, depositReserve.info.lendingMarket, - authority, + wallet.publicKey, ), ); } @@ -130,7 +99,7 @@ export const borrow = async ( instructions, [], accountRentExempt, - depositReserve.info.collateralMint, + depositReserve.info.collateral.mint, signers, ) : undefined; @@ -146,7 +115,7 @@ export const borrow = async ( const mint = (await cache.query( connection, - borrowReserve.info.liquidityMint, + borrowReserve.info.liquidity.mint, MintParser, )) as ParsedAccount; @@ -154,14 +123,14 @@ export const borrow = async ( } else if (amountType === BorrowAmountType.CollateralDepositAmount) { const mint = (await cache.query( connection, - depositReserve.info.collateralMint, + depositReserve.info.collateral.mint, MintParser, )) as ParsedAccount; amountLamports = toLamports(amount, mint?.info); fromLamports = amountLamports; } - const fromAccount = ensureSplAccount( + const sourceLiquidity = ensureSplAccount( instructions, finalCleanupInstructions, from, @@ -170,13 +139,13 @@ export const borrow = async ( signers, ); - let toAccount = await findOrCreateAccountByMint( + let destinationLiquidity = await findOrCreateAccountByMint( wallet.publicKey, wallet.publicKey, instructions, finalCleanupInstructions, accountRentExempt, - borrowReserve.info.liquidityMint, + borrowReserve.info.liquidity.mint, signers, ); @@ -203,72 +172,24 @@ export const borrow = async ( instructions = []; cleanupInstructions = [...finalCleanupInstructions]; - // create approval for transfer transactions - const transferAuthority = approve( - instructions, - cleanupInstructions, - fromAccount, - wallet.publicKey, - fromLamports, - false, - ); - signers.push(transferAuthority); - - const dexMarketAddress = borrowReserve.info.dexMarketOption - ? borrowReserve.info.dexMarket - : depositReserve.info.dexMarket; - const dexMarket = cache.get(dexMarketAddress); - - if (!dexMarket) { - throw new Error(`Dex market doesn't exist.`); - } - - const market = cache.get( - depositReserve.info.lendingMarket, - ) as ParsedAccount; - const dexOrderBookSide = market.info.quoteMint.equals( - depositReserve.info.liquidityMint, - ) - ? dexMarket?.info.asks - : dexMarket?.info.bids; - - const memory = createTempMemoryAccount( - instructions, - wallet.publicKey, - signers, - LENDING_PROGRAM_ID, - ); - instructions.push( - accrueInterestInstruction(depositReserve.pubkey, borrowReserve.pubkey), + // @FIXME: aggregator needed + refreshReserveInstruction(depositReserve.pubkey), + refreshReserveInstruction(borrowReserve.pubkey), ); // borrow instructions.push( - borrowInstruction( + borrowObligationLiquidityInstruction( amountLamports, - amountType, - fromAccount, - toAccount, - depositReserve.pubkey, - depositReserve.info.collateralSupply, - depositReserve.info.collateralFeesReceiver, - + borrowReserve.info.liquidity.supply, + destinationLiquidity, borrowReserve.pubkey, - borrowReserve.info.liquiditySupply, - + borrowReserve.info.liquidity.feeReceiver, obligation, - obligationMint, - obligationTokenOutput, - - depositReserve.info.lendingMarket, - authority, - transferAuthority.publicKey, - - dexMarketAddress, - dexOrderBookSide, - - memory, - + borrowReserve.info.lendingMarket, + lendingMarketAuthority, + // @FIXME: obligation owner + obligationOwner, hostFeeReceiver, ), ); diff --git a/packages/lending/src/actions/obligation.tsx b/packages/lending/src/actions/createAccount.tsx similarity index 69% rename from packages/lending/src/actions/obligation.tsx rename to packages/lending/src/actions/createAccount.tsx index 4543ff37..6ef61e93 100644 --- a/packages/lending/src/actions/obligation.tsx +++ b/packages/lending/src/actions/createAccount.tsx @@ -1,25 +1,26 @@ +import { LENDING_PROGRAM_ID } from '@oyster/common'; import { Account, PublicKey, SystemProgram, TransactionInstruction, } from '@solana/web3.js'; -import { utils } from '@oyster/common'; -import { LendingObligationLayout } from '../models'; -const { LENDING_PROGRAM_ID } = utils; -export function createUninitializedObligation( + +export function createAccount( instructions: TransactionInstruction[], payer: PublicKey, amount: number, signers: Account[], + space: number, ) { const account = new Account(); + instructions.push( SystemProgram.createAccount({ fromPubkey: payer, newAccountPubkey: account.publicKey, lamports: amount, - space: LendingObligationLayout.span, + space, programId: LENDING_PROGRAM_ID, }), ); diff --git a/packages/lending/src/actions/createObligation.tsx b/packages/lending/src/actions/createObligation.tsx new file mode 100644 index 00000000..dda8a029 --- /dev/null +++ b/packages/lending/src/actions/createObligation.tsx @@ -0,0 +1,18 @@ +import { Account, PublicKey, TransactionInstruction } from '@solana/web3.js'; +import { ObligationLayout } from '../models'; +import { createAccount } from './createAccount'; + +export function createObligation( + instructions: TransactionInstruction[], + payer: PublicKey, + amount: number, + signers: Account[], +) { + return createAccount( + instructions, + payer, + amount, + signers, + ObligationLayout.span, + ); +} diff --git a/packages/lending/src/actions/createReserve.tsx b/packages/lending/src/actions/createReserve.tsx new file mode 100644 index 00000000..71e8ec98 --- /dev/null +++ b/packages/lending/src/actions/createReserve.tsx @@ -0,0 +1,18 @@ +import { Account, PublicKey, TransactionInstruction } from '@solana/web3.js'; +import { ReserveLayout } from '../models'; +import { createAccount } from './createAccount'; + +export function createReserve( + instructions: TransactionInstruction[], + payer: PublicKey, + amount: number, + signers: Account[], +) { + return createAccount( + instructions, + payer, + amount, + signers, + ReserveLayout.span, + ); +} diff --git a/packages/lending/src/actions/deposit.tsx b/packages/lending/src/actions/depositReserveLiquidity.tsx similarity index 67% rename from packages/lending/src/actions/deposit.tsx rename to packages/lending/src/actions/depositReserveLiquidity.tsx index eb60ae99..1eca3cec 100644 --- a/packages/lending/src/actions/deposit.tsx +++ b/packages/lending/src/actions/depositReserveLiquidity.tsx @@ -1,20 +1,26 @@ +import { + actions, + contexts, + LENDING_PROGRAM_ID, + models, + notify, + TokenAccount, +} from '@oyster/common'; +import { AccountLayout } from '@solana/spl-token'; import { Account, Connection, PublicKey, TransactionInstruction, } from '@solana/web3.js'; -import { contexts, utils, models, actions, TokenAccount } from '@oyster/common'; import { - accrueInterestInstruction, - depositInstruction, + depositReserveLiquidityInstruction, initReserveInstruction, - LendingReserve, -} from './../models/lending'; -import { AccountLayout } from '@solana/spl-token'; + refreshReserveInstruction, + Reserve, +} from '../models'; const { sendTransaction } = contexts.Connection; -const { LENDING_PROGRAM_ID, notify } = utils; const { createUninitializedAccount, ensureSplAccount, @@ -22,10 +28,11 @@ const { } = actions; const { approve } = models; -export const deposit = async ( +// @FIXME +export const depositReserveLiquidity = async ( from: TokenAccount, amountLamports: number, - reserve: LendingReserve, + reserve: Reserve, reserveAddress: PublicKey, connection: Connection, wallet: any, @@ -47,12 +54,12 @@ export const deposit = async ( AccountLayout.span, ); - const [authority] = await PublicKey.findProgramAddress( + const [lendingMarketAuthority] = await PublicKey.findProgramAddress( [reserve.lendingMarket.toBuffer()], // which account should be authority LENDING_PROGRAM_ID, ); - const fromAccount = ensureSplAccount( + const sourceLiquidityAccount = ensureSplAccount( instructions, cleanupInstructions, from, @@ -65,27 +72,27 @@ export const deposit = async ( const transferAuthority = approve( instructions, cleanupInstructions, - fromAccount, + sourceLiquidityAccount, wallet.publicKey, amountLamports, ); signers.push(transferAuthority); - let toAccount: PublicKey; + let destinationCollateralAccount: PublicKey; if (isInitalized) { // get destination account - toAccount = await findOrCreateAccountByMint( + destinationCollateralAccount = await findOrCreateAccountByMint( wallet.publicKey, wallet.publicKey, instructions, cleanupInstructions, accountRentExempt, - reserve.collateralMint, + reserve.collateral.mint, signers, ); } else { - toAccount = createUninitializedAccount( + destinationCollateralAccount = createUninitializedAccount( instructions, wallet.publicKey, accountRentExempt, @@ -94,40 +101,42 @@ export const deposit = async ( } if (isInitalized) { - instructions.push(accrueInterestInstruction(reserveAddress)); + // @FIXME: aggregator needed + instructions.push(refreshReserveInstruction(reserveAddress)); // deposit instructions.push( - depositInstruction( + depositReserveLiquidityInstruction( amountLamports, - fromAccount, - toAccount, + sourceLiquidityAccount, + destinationCollateralAccount, + reserveAddress, + reserve.liquidity.supply, + reserve.collateral.mint, reserve.lendingMarket, - authority, + lendingMarketAuthority, transferAuthority.publicKey, - reserveAddress, - reserve.liquiditySupply, - reserve.collateralMint, ), ); } else { // TODO: finish reserve init + // @FIXME const MAX_UTILIZATION_RATE = 80; instructions.push( initReserveInstruction( amountLamports, MAX_UTILIZATION_RATE, - fromAccount, - toAccount, + sourceLiquidityAccount, + destinationCollateralAccount, reserveAddress, - reserve.liquidityMint, - reserve.liquiditySupply, - reserve.collateralMint, - reserve.collateralSupply, + reserve.liquidity.mint, + reserve.liquidity.supply, + reserve.collateral.mint, + reserve.collateral.supply, reserve.lendingMarket, - authority, + lendingMarketAuthority, transferAuthority.publicKey, - reserve.dexMarket, + reserve.aggregator, ), ); } diff --git a/packages/lending/src/actions/index.ts b/packages/lending/src/actions/index.ts index 8301458d..b6ab1d65 100644 --- a/packages/lending/src/actions/index.ts +++ b/packages/lending/src/actions/index.ts @@ -1,5 +1,5 @@ -export { borrow } from './borrow'; -export { deposit } from './deposit'; -export { repay } from './repay'; -export { withdraw } from './withdraw'; -export { liquidate } from './liquidate'; +export { borrowObligationLiquidity } from './borrowObligationLiquidity'; +export { depositReserveLiquidity } from './depositReserveLiquidity'; +export { repayObligationLiquidity } from './repayObligationLiquidity'; +export { redeemReserveCollateral } from './redeemReserveCollateral'; +export { liquidateObligation } from './liquidateObligation'; diff --git a/packages/lending/src/actions/liquidate.tsx b/packages/lending/src/actions/liquidateObligation.tsx similarity index 66% rename from packages/lending/src/actions/liquidate.tsx rename to packages/lending/src/actions/liquidateObligation.tsx index 4758ac98..e0614b2d 100644 --- a/packages/lending/src/actions/liquidate.tsx +++ b/packages/lending/src/actions/liquidateObligation.tsx @@ -1,46 +1,41 @@ import { - Account, - Connection, - PublicKey, - TransactionInstruction, -} from '@solana/web3.js'; -import { + createTempMemoryAccount, + ensureSplAccount, + findOrCreateAccountByMint, contexts, - utils, - actions, + LENDING_PROGRAM_ID, models, + notify, ParsedAccount, TokenAccount, } from '@oyster/common'; -import { - accrueInterestInstruction, - LendingReserve, -} from './../models/lending/reserve'; -import { liquidateInstruction } from './../models/lending/liquidate'; import { AccountLayout } from '@solana/spl-token'; -import { LendingMarket, LendingObligation } from '../models'; +import { Account, Connection, PublicKey, TransactionInstruction } from '@solana/web3.js'; +import { + LendingMarket, + liquidateObligationInstruction, + Obligation, + refreshReserveInstruction, + Reserve +} from '../models'; + const { cache } = contexts.Accounts; const { approve } = models; -const { - createTempMemoryAccount, - ensureSplAccount, - findOrCreateAccountByMint, -} = actions; const { sendTransaction } = contexts.Connection; -const { LENDING_PROGRAM_ID, notify } = utils; -export const liquidate = async ( +// @FIXME +export const liquidateObligation = async ( connection: Connection, wallet: any, from: TokenAccount, // liquidity account amountLamports: number, // in liquidty token (lamports) // which loan to repay - obligation: ParsedAccount, + obligation: ParsedAccount, - repayReserve: ParsedAccount, + repayReserve: ParsedAccount, - withdrawReserve: ParsedAccount, + withdrawReserve: ParsedAccount, ) => { notify({ message: 'Repaying funds...', @@ -57,7 +52,7 @@ export const liquidate = async ( AccountLayout.span, ); - const [authority] = await PublicKey.findProgramAddress( + const [lendingMarketAuthority] = await PublicKey.findProgramAddress( [repayReserve.info.lendingMarket.toBuffer()], LENDING_PROGRAM_ID, ); @@ -88,16 +83,16 @@ export const liquidate = async ( instructions, cleanupInstructions, accountRentExempt, - withdrawReserve.info.collateralMint, + withdrawReserve.info.collateral.mint, signers, ); - const dexMarketAddress = repayReserve.info.dexMarketOption - ? repayReserve.info.dexMarket - : withdrawReserve.info.dexMarket; - const dexMarket = cache.get(dexMarketAddress); + const aggregatorAddress = repayReserve.info.liquidity.aggregatorOption + ? repayReserve.info.liquidity.aggregator + : withdrawReserve.info.liquidity.aggregator; + const aggregator = cache.get(aggregatorAddress); - if (!dexMarket) { + if (!aggregator) { throw new Error(`Dex market doesn't exist.`); } @@ -105,11 +100,11 @@ export const liquidate = async ( withdrawReserve.info.lendingMarket, ) as ParsedAccount; - const dexOrderBookSide = market.info.quoteMint.equals( - repayReserve.info.liquidityMint, + const dexOrderBookSide = market.info.quoteTokenMint.equals( + repayReserve.info.liquidity.mint, ) - ? dexMarket?.info.asks - : dexMarket?.info.bids; + ? aggregator?.info.asks + : aggregator?.info.bids; const memory = createTempMemoryAccount( instructions, @@ -119,25 +114,24 @@ export const liquidate = async ( ); instructions.push( - accrueInterestInstruction(repayReserve.pubkey, withdrawReserve.pubkey), + // @FIXME: aggregator needed + refreshReserveInstruction(repayReserve.pubkey), + refreshReserveInstruction(withdrawReserve.pubkey), ); instructions.push( - liquidateInstruction( + liquidateObligationInstruction( amountLamports, fromAccount, toAccount, repayReserve.pubkey, - repayReserve.info.liquiditySupply, + repayReserve.info.liquidity.supply, withdrawReserve.pubkey, - withdrawReserve.info.collateralSupply, + withdrawReserve.info.collateral.supply, obligation.pubkey, repayReserve.info.lendingMarket, - authority, + lendingMarketAuthority, transferAuthority.publicKey, - dexMarketAddress, - dexOrderBookSide, - memory, ), ); diff --git a/packages/lending/src/actions/withdraw.tsx b/packages/lending/src/actions/redeemReserveCollateral.tsx similarity index 68% rename from packages/lending/src/actions/withdraw.tsx rename to packages/lending/src/actions/redeemReserveCollateral.tsx index 9852e8a4..396a8955 100644 --- a/packages/lending/src/actions/withdraw.tsx +++ b/packages/lending/src/actions/redeemReserveCollateral.tsx @@ -1,25 +1,32 @@ +import { + contexts, + findOrCreateAccountByMint, + LENDING_PROGRAM_ID, + models, + notify, + TokenAccount, +} from '@oyster/common'; +import { AccountLayout } from '@solana/spl-token'; import { Account, Connection, PublicKey, TransactionInstruction, } from '@solana/web3.js'; -import { contexts, utils, actions, models, TokenAccount } from '@oyster/common'; import { - accrueInterestInstruction, - LendingReserve, - withdrawInstruction, -} from './../models/lending'; -import { AccountLayout } from '@solana/spl-token'; + redeemReserveCollateral, + refreshReserveInstruction, + Reserve, +} from '../models'; + const { approve } = models; -const { findOrCreateAccountByMint } = actions; const { sendTransaction } = contexts.Connection; -const { LENDING_PROGRAM_ID, notify } = utils; -export const withdraw = async ( +// @FIXME +export const redeemReserveCollateral = async ( from: TokenAccount, // CollateralAccount amountLamports: number, // in collateral token (lamports) - reserve: LendingReserve, + reserve: Reserve, reserveAddress: PublicKey, connection: Connection, wallet: any, @@ -39,18 +46,18 @@ export const withdraw = async ( AccountLayout.span, ); - const [authority] = await PublicKey.findProgramAddress( + const [lendingMarketAuthority] = await PublicKey.findProgramAddress( [reserve.lendingMarket.toBuffer()], LENDING_PROGRAM_ID, ); - const fromAccount = from.pubkey; + const sourceCollateral = from.pubkey; // create approval for transfer transactions const transferAuthority = approve( instructions, cleanupInstructions, - fromAccount, + sourceCollateral, wallet.publicKey, amountLamports, ); @@ -58,28 +65,29 @@ export const withdraw = async ( signers.push(transferAuthority); // get destination account - const toAccount = await findOrCreateAccountByMint( + const destinationLiquidity = await findOrCreateAccountByMint( wallet.publicKey, wallet.publicKey, instructions, cleanupInstructions, accountRentExempt, - reserve.liquidityMint, + reserve.liquidity.mint, signers, ); - instructions.push(accrueInterestInstruction(reserveAddress)); + // @FIXME: aggregator needed + instructions.push(refreshReserveInstruction(reserveAddress)); instructions.push( - withdrawInstruction( + redeemReserveCollateral( amountLamports, - fromAccount, - toAccount, + sourceCollateral, + destinationLiquidity, reserveAddress, - reserve.collateralMint, - reserve.liquiditySupply, + reserve.collateral.mint, + reserve.liquidity.supply, reserve.lendingMarket, - authority, + lendingMarketAuthority, transferAuthority.publicKey, ), ); diff --git a/packages/lending/src/actions/repay.tsx b/packages/lending/src/actions/repayObligationLiquidity.tsx similarity index 70% rename from packages/lending/src/actions/repay.tsx rename to packages/lending/src/actions/repayObligationLiquidity.tsx index 7e8ac77a..68f545c4 100644 --- a/packages/lending/src/actions/repay.tsx +++ b/packages/lending/src/actions/repayObligationLiquidity.tsx @@ -1,43 +1,42 @@ -import { - Account, - Connection, - PublicKey, - TransactionInstruction, -} from '@solana/web3.js'; import { contexts, - utils, - actions, + createTokenAccount, + findOrCreateAccountByMint, + LENDING_PROGRAM_ID, models, + notify, ParsedAccount, + TOKEN_PROGRAM_ID, TokenAccount, } from '@oyster/common'; - +import { AccountLayout, NATIVE_MINT, Token } from '@solana/spl-token'; import { - accrueInterestInstruction, - LendingReserve, -} from './../models/lending/reserve'; -import { repayInstruction } from './../models/lending/repay'; -import { AccountLayout, Token, NATIVE_MINT } from '@solana/spl-token'; + Account, + Connection, + PublicKey, + TransactionInstruction, +} from '@solana/web3.js'; +import { + Obligation, + refreshReserveInstruction, + repayObligationLiquidityInstruction, + Reserve, +} from '../models'; -import { LendingObligation } from '../models'; const { approve } = models; -const { createTokenAccount, findOrCreateAccountByMint } = actions; const { sendTransaction } = contexts.Connection; -const { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID, notify } = utils; -export const repay = async ( +// @FIXME +export const repayObligationLiquidity = async ( from: TokenAccount, repayAmount: number, // which loan to repay - obligation: ParsedAccount, - - obligationToken: TokenAccount, + obligation: ParsedAccount, - repayReserve: ParsedAccount, + repayReserve: ParsedAccount, - withdrawReserve: ParsedAccount, + withdrawReserve: ParsedAccount, connection: Connection, wallet: any, @@ -57,7 +56,7 @@ export const repay = async ( AccountLayout.span, ); - const [authority] = await PublicKey.findProgramAddress( + const [lendingMarketAuthority] = await PublicKey.findProgramAddress( [repayReserve.info.lendingMarket.toBuffer()], LENDING_PROGRAM_ID, ); @@ -65,7 +64,7 @@ export const repay = async ( let fromAccount = from.pubkey; if ( wallet.publicKey.equals(fromAccount) && - repayReserve.info.liquidityMint.equals(NATIVE_MINT) + repayReserve.info.liquidity.mint.equals(NATIVE_MINT) ) { fromAccount = createTokenAccount( instructions, @@ -103,10 +102,11 @@ export const repay = async ( instructions, cleanupInstructions, accountRentExempt, - withdrawReserve.info.collateralMint, + withdrawReserve.info.collateral.mint, signers, ); + // @FIXME: obligation tokens // create approval for transfer transactions approve( instructions, @@ -120,23 +120,20 @@ export const repay = async ( ); instructions.push( - accrueInterestInstruction(repayReserve.pubkey, withdrawReserve.pubkey), + // @FIXME: aggregator needed + refreshReserveInstruction(repayReserve.pubkey), + refreshReserveInstruction(withdrawReserve.pubkey), ); instructions.push( - repayInstruction( + repayObligationLiquidityInstruction( repayAmount, fromAccount, toAccount, repayReserve.pubkey, - repayReserve.info.liquiditySupply, - withdrawReserve.pubkey, - withdrawReserve.info.collateralSupply, obligation.pubkey, - obligation.info.tokenMint, - obligationToken.pubkey, repayReserve.info.lendingMarket, - authority, + lendingMarketAuthority, transferAuthority.publicKey, ), ); diff --git a/packages/lending/src/components/BarChartStatistic/index.tsx b/packages/lending/src/components/BarChartStatistic/index.tsx index fd7ab6b0..ad0bed61 100644 --- a/packages/lending/src/components/BarChartStatistic/index.tsx +++ b/packages/lending/src/components/BarChartStatistic/index.tsx @@ -1,5 +1,5 @@ -import { Statistic } from "antd"; -import React from "react"; +import { Statistic } from 'antd'; +import React from 'react'; export const BarChartStatistic = (props: { items: T[]; @@ -9,14 +9,14 @@ export const BarChartStatistic = (props: { getPct: (item: T) => number; }) => { const colors = [ - "#003f5c", - "#2f4b7c", - "#665191", - "#a05195", - "#d45087", - "#f95d6a", - "#ff7c43", - "#ffa600", + '#003f5c', + '#2f4b7c', + '#665191', + '#a05195', + '#d45087', + '#f95d6a', + '#ff7c43', + '#ffa600', ].reverse(); return ( @@ -25,12 +25,12 @@ export const BarChartStatistic = (props: { valueRender={() => (
{props.items.map((item, i) => ( @@ -38,7 +38,7 @@ export const BarChartStatistic = (props: { key={props.name(item)} title={props.name(item)} style={{ - overflow: "hidden", + overflow: 'hidden', width: `${100 * props.getPct(item)}%`, backgroundColor: (props.color && props.color(item)) || diff --git a/packages/lending/src/components/BorrowInput/index.tsx b/packages/lending/src/components/BorrowInput/index.tsx index c1202833..77e3033c 100644 --- a/packages/lending/src/components/BorrowInput/index.tsx +++ b/packages/lending/src/components/BorrowInput/index.tsx @@ -1,37 +1,34 @@ +import { + ActionConfirmation, + BackButton, + ConnectButton, + contexts, + ParsedAccount, +} from '@oyster/common'; +import { Card } from 'antd'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; + +import { borrowObligationLiquidity } from '../../actions'; +import { LABELS } from '../../constants'; +import { useMidPriceInUSD } from '../../contexts/market'; import { useSliderInput, useUserBalance, useUserDeposits, useUserObligationByReserve, } from '../../hooks'; -import { - BorrowAmountType, - LendingReserve, - LendingReserveParser, -} from '../../models'; -import { Card } from 'antd'; -import { - contexts, - ParsedAccount, - ConnectButton, - BackButton, - ActionConfirmation, -} from '@oyster/common'; - -import { borrow } from '../../actions'; -import './style.less'; -import { LABELS } from '../../constants'; +import { BorrowAmountType, Reserve, ReserveParser } from '../../models'; import CollateralInput from '../CollateralInput'; -import { useMidPriceInUSD } from '../../contexts/market'; import { RiskSlider } from '../RiskSlider'; +import './style.less'; + const { useWallet } = contexts.Wallet; const { useConnection } = contexts.Connection; const { cache } = contexts.Accounts; export const BorrowInput = (props: { className?: string; - reserve: ParsedAccount; + reserve: ParsedAccount; }) => { const connection = useConnection(); const { wallet } = useWallet(); @@ -42,26 +39,26 @@ export const BorrowInput = (props: { const borrowReserve = props.reserve; - const [collateralReserveKey, setCollateralReserveKey] = useState(); + const [depositReserveKey, setCollateralReserveKey] = useState(); - const collateralReserve = useMemo(() => { + const depositReserve = useMemo(() => { const id: string = cache - .byParser(LendingReserveParser) - .find(acc => acc === collateralReserveKey) || ''; + .byParser(ReserveParser) + .find(acc => acc === depositReserveKey) || ''; - return cache.get(id) as ParsedAccount; - }, [collateralReserveKey]); + return cache.get(id) as ParsedAccount; + }, [depositReserveKey]); const borrowPrice = useMidPriceInUSD( - borrowReserve.info.liquidityMint.toBase58(), + borrowReserve.info.liquidity.mint.toBase58(), ).price; const collateralPrice = useMidPriceInUSD( - collateralReserve?.info.liquidityMint.toBase58(), + depositReserve?.info.liquidity.mint.toBase58(), )?.price; const include = useMemo( - () => new Set([collateralReserve?.pubkey.toBase58()]), - [collateralReserve], + () => new Set([depositReserve?.pubkey.toBase58()]), + [depositReserve], ); const exclude = useMemo(() => new Set([]), []); @@ -84,7 +81,7 @@ export const BorrowInput = (props: { const { value, setValue, pct } = useSliderInput(convert); useEffect(() => { - if (collateralReserve && lastTyped === 'collateral') { + if (depositReserve && lastTyped === 'collateral') { const ltv = borrowReserve.info.config.loanToValueRatio / 100; if (collateralValue) { @@ -98,7 +95,7 @@ export const BorrowInput = (props: { } }, [ lastTyped, - collateralReserve, + depositReserve, collateralPrice, borrowPrice, borrowReserve, @@ -107,7 +104,7 @@ export const BorrowInput = (props: { ]); useEffect(() => { - if (collateralReserve && lastTyped === 'borrow') { + if (depositReserve && lastTyped === 'borrow') { const ltv = borrowReserve.info.config.loanToValueRatio / 100; if (value) { @@ -121,7 +118,7 @@ export const BorrowInput = (props: { } }, [ lastTyped, - collateralReserve, + depositReserve, collateralPrice, borrowPrice, borrowReserve, @@ -130,13 +127,13 @@ export const BorrowInput = (props: { const { userObligationsByReserve } = useUserObligationByReserve( borrowReserve?.pubkey, - collateralReserve?.pubkey, + depositReserve?.pubkey, ); const { accounts: fromAccounts } = useUserBalance( - collateralReserve?.info.collateralMint, + depositReserve?.info.collateral.mint, ); const onBorrow = useCallback(() => { - if (!collateralReserve) { + if (!depositReserve) { return; } @@ -144,7 +141,7 @@ export const BorrowInput = (props: { (async () => { try { - await borrow( + await borrowObligationLiquidity( connection, wallet, @@ -153,7 +150,7 @@ export const BorrowInput = (props: { // TODO: switch to collateral when user is using slider BorrowAmountType.LiquidityBorrowAmount, borrowReserve, - collateralReserve, + depositReserve, // TODO: select exsisting obligations by collateral reserve userObligationsByReserve.length > 0 @@ -179,7 +176,7 @@ export const BorrowInput = (props: { wallet, value, setValue, - collateralReserve, + depositReserve, borrowReserve, fromAccounts, userObligationsByReserve, diff --git a/packages/lending/src/components/CollateralInput/index.tsx b/packages/lending/src/components/CollateralInput/index.tsx index aaefe70a..e838a892 100644 --- a/packages/lending/src/components/CollateralInput/index.tsx +++ b/packages/lending/src/components/CollateralInput/index.tsx @@ -1,18 +1,21 @@ +import { + contexts, + getTokenName, + NumericInput, + ParsedAccount, + TokenDisplay, + TokenIcon, +} from '@oyster/common'; +import { Card, Select } from 'antd'; import React, { useEffect, useState } from 'react'; -import { contexts, utils, ParsedAccount, NumericInput, TokenIcon, TokenDisplay } from '@oyster/common'; import { useLendingReserves, useUserBalance, useUserDeposits, } from '../../hooks'; -import { - LendingReserve, - LendingMarket, - LendingReserveParser, -} from '../../models'; -import { Card, Select } from 'antd'; +import { LendingMarket, Reserve, ReserveParser } from '../../models'; import './style.less'; -const { getTokenName } = utils; + const { cache } = contexts.Accounts; const { useConnectionConfig } = contexts.Connection; @@ -23,7 +26,7 @@ const { Option } = Select; export default function CollateralInput(props: { title: string; amount?: number | null; - reserve: LendingReserve; + reserve: Reserve; disabled?: boolean; onCollateralReserve?: (id: string) => void; onLeverage?: (leverage: number) => void; @@ -34,10 +37,10 @@ export default function CollateralInput(props: { showLeverageSelector?: boolean; leverage?: number; }) { - const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint); + const { balance: tokenBalance } = useUserBalance(props.reserve.liquidity.mint); const { reserveAccounts } = useLendingReserves(); const { tokenMap } = useConnectionConfig(); - const [collateralReserve, setCollateralReserve] = useState(); + const [depositReserve, setCollateralReserve] = useState(); const [balance, setBalance] = useState(0); const [lastAmount, setLastAmount] = useState(''); const userDeposits = useUserDeposits(); @@ -48,29 +51,29 @@ export default function CollateralInput(props: { } else { const id: string = cache - .byParser(LendingReserveParser) - .find(acc => acc === collateralReserve) || ''; - const parser = cache.get(id) as ParsedAccount; + .byParser(ReserveParser) + .find(acc => acc === depositReserve) || ''; + const parser = cache.get(id) as ParsedAccount; if (parser) { const collateralDeposit = userDeposits.userDeposits.find( u => - u.reserve.info.liquidityMint.toBase58() === - parser.info.liquidityMint.toBase58(), + u.reserve.info.liquidity.mint.toBase58() === + parser.info.liquidity.mint.toBase58(), ); if (collateralDeposit) setBalance(collateralDeposit.info.amount); else setBalance(0); } } - }, [collateralReserve, userDeposits, tokenBalance, props.useWalletBalance]); + }, [depositReserve, userDeposits, tokenBalance, props.useWalletBalance]); const market = cache.get( props.reserve.lendingMarket, ) as ParsedAccount; if (!market) return null; - const onlyQuoteAllowed = !props.reserve?.liquidityMint?.equals( - market?.info?.quoteMint, + const onlyQuoteAllowed = !props.reserve?.liquidity.mint?.equals( + market?.info?.quoteTokenMint, ); const filteredReserveAccounts = reserveAccounts @@ -78,11 +81,11 @@ export default function CollateralInput(props: { .filter( reserve => !onlyQuoteAllowed || - reserve.info.liquidityMint.equals(market.info.quoteMint), + reserve.info.liquidity.mint.equals(market.info.quoteTokenMint), ); if ( - !collateralReserve && + !depositReserve && props.useFirstReserve && filteredReserveAccounts.length ) { @@ -90,7 +93,7 @@ export default function CollateralInput(props: { setCollateralReserve(address); } const renderReserveAccounts = filteredReserveAccounts.map(reserve => { - const mint = reserve.info.liquidityMint.toBase58(); + const mint = reserve.info.liquidity.mint.toBase58(); const address = reserve.pubkey.toBase58(); const name = getTokenName(tokenMap, mint); return ( @@ -187,7 +190,7 @@ export default function CollateralInput(props: { showSearch style={{ minWidth: 150 }} placeholder="CCY" - value={collateralReserve} + value={depositReserve} onChange={item => { if (props.onCollateralReserve) props.onCollateralReserve(item); setCollateralReserve(item); @@ -200,12 +203,12 @@ export default function CollateralInput(props: { ) : ( )} diff --git a/packages/lending/src/components/CollateralSelector/index.tsx b/packages/lending/src/components/CollateralSelector/index.tsx index 12842ce8..5fafe1bf 100644 --- a/packages/lending/src/components/CollateralSelector/index.tsx +++ b/packages/lending/src/components/CollateralSelector/index.tsx @@ -1,10 +1,15 @@ +import { + contexts, + formatAmount, + getTokenName, + ParsedAccount, + TokenIcon, +} from '@oyster/common'; +import { Select } from 'antd'; import React from 'react'; import { useLendingReserves, UserDeposit, useUserDeposits } from '../../hooks'; -import { LendingMarket, LendingReserve } from '../../models'; -import { Select } from 'antd'; -import { contexts, utils, ParsedAccount, TokenIcon } from '@oyster/common'; +import { LendingMarket, Reserve } from '../../models'; -const { getTokenName, formatAmount } = utils; const { cache } = contexts.Accounts; const { useConnectionConfig } = contexts.Connection; @@ -12,7 +17,7 @@ const { Option } = Select; export const CollateralItem = (props: { mint: string; - reserve: ParsedAccount; + reserve: ParsedAccount; userDeposit?: UserDeposit; name: string; }) => { @@ -32,8 +37,8 @@ export const CollateralItem = (props: { }; export const CollateralSelector = (props: { - reserve: LendingReserve; - collateralReserve?: string; + reserve: Reserve; + depositReserve?: string; disabled?: boolean; onCollateralReserve?: (id: string) => void; }) => { @@ -46,10 +51,10 @@ export const CollateralSelector = (props: { ) as ParsedAccount; if (!market) return null; - const quoteMintAddress = market?.info?.quoteMint?.toBase58(); + const quoteTokenMintAddress = market?.info?.quoteTokenMint?.toBase58(); const onlyQuoteAllowed = - props.reserve?.liquidityMint?.toBase58() !== quoteMintAddress; + props.reserve?.liquidity.mint?.toBase58() !== quoteTokenMintAddress; return (