From d67b410bfaebce87efc5bbcd03b102b042ddddca Mon Sep 17 00:00:00 2001 From: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com> Date: Fri, 22 Jan 2021 22:12:17 -0600 Subject: [PATCH 1/7] fix: resolves #41 --- src/models/lending/lending.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/models/lending/lending.ts b/src/models/lending/lending.ts index 49c31ad..07206b9 100644 --- a/src/models/lending/lending.ts +++ b/src/models/lending/lending.ts @@ -1,9 +1,10 @@ export enum LendingInstruction { InitLendingMarket = 0, InitReserve = 1, - DepositReserveLiquidity = 2, - WithdrawReserveLiquidity = 3, - BorrowLiquidity = 4, - RepayOblogationLiquidity = 5, - LiquidateObligation = 6, + InitObligation = 2, + DepositReserveLiquidity = 3, + WithdrawReserveLiquidity = 4, + BorrowLiquidity = 5, + RepayOblogationLiquidity = 6, + LiquidateObligation = 7, } From 5c948d83d313788bd6b4ae5815a904ae520455d5 Mon Sep 17 00:00:00 2001 From: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com> Date: Fri, 22 Jan 2021 22:13:22 -0600 Subject: [PATCH 2/7] feat: init obligation. resolves #39 --- src/actions/borrow.tsx | 19 ++++++++++-- src/models/lending/borrow.ts | 23 ++++++-------- src/models/lending/obligation.ts | 51 +++++++++++++++++++++++++++++++- 3 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/actions/borrow.tsx b/src/actions/borrow.tsx index 220b7c8..df442b2 100644 --- a/src/actions/borrow.tsx +++ b/src/actions/borrow.tsx @@ -26,6 +26,7 @@ import { BorrowAmountType, LendingObligation, approve, + initObligationInstruction, } from "../models"; import { toLamports } from "../utils/utils"; @@ -185,7 +186,22 @@ export const borrow = async ( ) : undefined; - // deposit + if (!obligationAccount) { + instructions.push( + initObligationInstruction( + depositReserve.pubkey, + borrowReserve.pubkey, + obligation, + obligationMint, + obligationTokenOutput, + wallet.publicKey, + depositReserve.info.lendingMarket, + authority, + ) + ); + } + + // borrow instructions.push( borrowInstruction( amountLamports, @@ -202,7 +218,6 @@ export const borrow = async ( obligation, obligationMint, obligationTokenOutput, - wallet.publicKey, depositReserve.info.lendingMarket, authority, diff --git a/src/models/lending/borrow.ts b/src/models/lending/borrow.ts index 999bb75..ab740c4 100644 --- a/src/models/lending/borrow.ts +++ b/src/models/lending/borrow.ts @@ -1,4 +1,4 @@ -import { PublicKey, SYSVAR_CLOCK_PUBKEY, SYSVAR_RENT_PUBKEY, TransactionInstruction } from '@solana/web3.js'; +import { PublicKey, SYSVAR_CLOCK_PUBKEY, TransactionInstruction } from '@solana/web3.js'; import BN from 'bn.js'; import * as BufferLayout from 'buffer-layout'; import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; @@ -24,16 +24,14 @@ export enum BorrowAmountType { /// 6. `[writable]` Obligation /// 7. `[writable]` Obligation token mint /// 8. `[writable]` Obligation token output -/// 9. `[]` Obligation token owner -/// 10 `[]` Lending market account. -/// 11 `[]` Derived lending market authority. -/// 12 `[]` User transfer authority ($authority). -/// 13 `[]` Dex market -/// 14 `[]` Dex market order book side -/// 15 `[]` Temporary memory -/// 16 `[]` Clock sysvar -/// 17 `[]` Rent sysvar -/// 18 '[]` Token program id +/// 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, @@ -49,7 +47,6 @@ export const borrowInstruction = ( obligation: PublicKey, obligationMint: PublicKey, obligationTokenOutput: PublicKey, - obligationTokenOwner: PublicKey, lendingMarket: PublicKey, lendingMarketAuthority: PublicKey, @@ -98,7 +95,6 @@ export const borrowInstruction = ( { 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 }, @@ -108,7 +104,6 @@ export const borrowInstruction = ( { pubkey: dexOrderBookSide, isSigner: false, isWritable: false }, { pubkey: memory, 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 }, ]; diff --git a/src/models/lending/obligation.ts b/src/models/lending/obligation.ts index 7da30b6..e238e58 100644 --- a/src/models/lending/obligation.ts +++ b/src/models/lending/obligation.ts @@ -1,6 +1,8 @@ -import { AccountInfo, PublicKey } from "@solana/web3.js"; +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 { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../../utils/ids"; import * as Layout from "./../../utils/layout"; export const LendingObligationLayout: typeof BufferLayout.Structure = BufferLayout.struct( @@ -60,3 +62,50 @@ export const LendingObligationParser = ( 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: true }, + { pubkey: borrowReserve, isSigner: false, isWritable: true }, + { 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, + }); +}; From 7062479f1b2cde8a827aa84da1f83a7a79f9b0c8 Mon Sep 17 00:00:00 2001 From: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com> Date: Fri, 22 Jan 2021 22:18:23 -0600 Subject: [PATCH 3/7] fxi: update lending market layout --- src/models/lending/market.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/models/lending/market.ts b/src/models/lending/market.ts index 434ab09..1c1b3e7 100644 --- a/src/models/lending/market.ts +++ b/src/models/lending/market.ts @@ -6,6 +6,7 @@ export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.s [ BufferLayout.u8('version'), BufferLayout.u8('bumpSeed'), + Layout.publicKey("owner"), Layout.publicKey("quoteMint"), Layout.publicKey("tokenProgramId"), From 7a7250ea62cd8468a9f7fa830e79d3f0f98adfc3 Mon Sep 17 00:00:00 2001 From: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com> Date: Fri, 22 Jan 2021 22:57:25 -0600 Subject: [PATCH 4/7] feat: add AccrueReserveInterest. resolves #38 --- src/actions/borrow.tsx | 71 ++++++++++++++++---------------- src/models/lending/borrow.ts | 4 +- src/models/lending/lending.ts | 1 + src/models/lending/liquidate.ts | 4 +- src/models/lending/obligation.ts | 17 +++++++- src/models/lending/reserve.ts | 26 ++++++++++++ 6 files changed, 82 insertions(+), 41 deletions(-) diff --git a/src/actions/borrow.tsx b/src/actions/borrow.tsx index df442b2..3fdb2d1 100644 --- a/src/actions/borrow.tsx +++ b/src/actions/borrow.tsx @@ -56,6 +56,11 @@ export const borrow = async ( let instructions: TransactionInstruction[] = []; let cleanupInstructions: TransactionInstruction[] = []; + const [authority] = await PublicKey.findProgramAddress( + [depositReserve.info.lendingMarket.toBuffer()], + LENDING_PROGRAM_ID + ); + const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span); const obligation = existingObligation @@ -90,6 +95,35 @@ export const borrow = async ( signers ); + if (!obligationAccount) { + instructions.push( + initObligationInstruction( + depositReserve.pubkey, + borrowReserve.pubkey, + obligation, + obligationMint, + obligationTokenOutput, + wallet.publicKey, + depositReserve.info.lendingMarket, + authority, + ) + ); + } + + // Creates host fee account if it doesn't exsist + let hostFeeReceiver = LEND_HOST_FEE_ADDRESS + ? findOrCreateAccountByMint( + wallet.publicKey, + LEND_HOST_FEE_ADDRESS, + instructions, + cleanupInstructions, + accountRentExempt, + depositReserve.info.collateralMint, + signers + ) + : undefined; + + if (instructions.length > 0) { // create all accounts in one transaction let tx = await sendTransaction(connection, wallet, instructions, [...signers]); @@ -111,11 +145,6 @@ export const borrow = async ( instructions = []; cleanupInstructions = []; - const [authority] = await PublicKey.findProgramAddress( - [depositReserve.info.lendingMarket.toBuffer()], - LENDING_PROGRAM_ID - ); - let amountLamports: number = 0; let fromLamports: number = 0; if (amountType === BorrowAmountType.LiquidityBorrowAmount) { @@ -173,34 +202,6 @@ export const borrow = async ( const memory = createTempMemoryAccount(instructions, wallet.publicKey, signers, LENDING_PROGRAM_ID); - // Creates host fee account if it doesn't exsist - let hostFeeReceiver = LEND_HOST_FEE_ADDRESS - ? findOrCreateAccountByMint( - wallet.publicKey, - LEND_HOST_FEE_ADDRESS, - instructions, - cleanupInstructions, - accountRentExempt, - depositReserve.info.collateralMint, - signers - ) - : undefined; - - if (!obligationAccount) { - instructions.push( - initObligationInstruction( - depositReserve.pubkey, - borrowReserve.pubkey, - obligation, - obligationMint, - obligationTokenOutput, - wallet.publicKey, - depositReserve.info.lendingMarket, - authority, - ) - ); - } - // borrow instructions.push( borrowInstruction( @@ -239,8 +240,8 @@ export const borrow = async ( type: 'success', description: `Transaction - ${tx}`, }); - } catch { - // TODO: + } catch (ex) { + console.error(ex) throw new Error(); } }; diff --git a/src/models/lending/borrow.ts b/src/models/lending/borrow.ts index ab740c4..de71b64 100644 --- a/src/models/lending/borrow.ts +++ b/src/models/lending/borrow.ts @@ -17,7 +17,7 @@ export enum BorrowAmountType { /// 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. `[writable]` Deposit reserve account. +/// 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 @@ -78,7 +78,7 @@ export const borrowInstruction = ( const keys = [ { pubkey: from, isSigner: false, isWritable: true }, { pubkey: to, isSigner: false, isWritable: true }, - { pubkey: depositReserve, isSigner: false, isWritable: true }, + { pubkey: depositReserve, isSigner: false, isWritable: false }, { pubkey: depositReserveCollateralSupply, isSigner: false, diff --git a/src/models/lending/lending.ts b/src/models/lending/lending.ts index 07206b9..e6c4334 100644 --- a/src/models/lending/lending.ts +++ b/src/models/lending/lending.ts @@ -7,4 +7,5 @@ export enum LendingInstruction { BorrowLiquidity = 5, RepayOblogationLiquidity = 6, LiquidateObligation = 7, + AccrueReserveInterest = 8, } diff --git a/src/models/lending/liquidate.ts b/src/models/lending/liquidate.ts index 7e55e80..386dea6 100644 --- a/src/models/lending/liquidate.ts +++ b/src/models/lending/liquidate.ts @@ -10,7 +10,7 @@ import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; /// 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. +/// 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 @@ -57,7 +57,7 @@ export const liquidateInstruction = ( { pubkey: repayReserveAccount, isSigner: false, isWritable: true }, { pubkey: repayReserveLiquiditySupply, isSigner: false, isWritable: true }, - { pubkey: withdrawReserve, isSigner: false, isWritable: true }, + { pubkey: withdrawReserve, isSigner: false, isWritable: false }, { pubkey: withdrawReserveCollateralSupply, isSigner: false, diff --git a/src/models/lending/obligation.ts b/src/models/lending/obligation.ts index e238e58..567620f 100644 --- a/src/models/lending/obligation.ts +++ b/src/models/lending/obligation.ts @@ -63,6 +63,19 @@ export const healthFactorToRiskColor = (health: number) => { return ''; } +/// Initializes a new loan obligation. +/// /// +/// 0. `[]` Deposit reserve account. /// 0. `[]` Deposit reserve account. +/// 1. `[writable]` Borrow reserve account. /// 1. `[]` Borrow reserve account. +/// 2. `[writable]` Obligation /// 2. `[writable]` Obligation +/// 3. `[writable]` Obligation token mint /// 3. `[writable]` Obligation token mint +/// 4. `[writable]` Obligation token output /// 4. `[writable]` Obligation token output +/// 5. `[]` Obligation token owner /// 5. `[]` Obligation token owner +/// 6. `[]` Lending market account. /// 6. `[]` Lending market account. +/// 7. `[]` Derived lending market authority. /// 7. `[]` Derived lending market authority. +/// 8. `[]` Clock sysvar /// 8. `[]` Clock sysvar +/// 9. `[]` Rent sysvar /// 9. `[]` Rent sysvar +/// 10 '[]` Token program id /// 10 '[]` Token program id export const initObligationInstruction = ( depositReserve: PublicKey, borrowReserve: PublicKey, @@ -89,8 +102,8 @@ export const initObligationInstruction = ( ); const keys = [ - { pubkey: depositReserve, isSigner: false, isWritable: true }, - { pubkey: borrowReserve, isSigner: false, isWritable: true }, + { 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 }, diff --git a/src/models/lending/reserve.ts b/src/models/lending/reserve.ts index 6356f70..4bf053e 100644 --- a/src/models/lending/reserve.ts +++ b/src/models/lending/reserve.ts @@ -204,6 +204,32 @@ export const initReserveInstruction = ( }); }; +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); From 01bae0f1c85099fb490033f660a7f87c0399dfe5 Mon Sep 17 00:00:00 2001 From: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com> Date: Fri, 22 Jan 2021 23:04:23 -0600 Subject: [PATCH 5/7] feat: accrue interest, resolves #38 --- src/actions/borrow.tsx | 10 ++++++++-- src/actions/deposit.tsx | 7 +++++++ src/actions/liquidate.tsx | 9 ++++++++- src/actions/repay.tsx | 11 ++++++++--- src/actions/withdraw.tsx | 8 +++++++- src/models/lending/reserve.ts | 2 +- 6 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/actions/borrow.tsx b/src/actions/borrow.tsx index 3fdb2d1..a48554e 100644 --- a/src/actions/borrow.tsx +++ b/src/actions/borrow.tsx @@ -6,7 +6,7 @@ import { } from "@solana/web3.js"; import { sendTransaction } from "../contexts/connection"; import { notify } from "../utils/notifications"; -import { LendingReserve } from "./../models/lending/reserve"; +import { accrueInterestInstruction, LendingReserve } from "./../models/lending/reserve"; import { AccountLayout, MintInfo, MintLayout } from "@solana/spl-token"; import { LENDING_PROGRAM_ID, LEND_HOST_FEE_ADDRESS } from "../utils/ids"; import { @@ -123,7 +123,6 @@ export const borrow = async ( ) : undefined; - if (instructions.length > 0) { // create all accounts in one transaction let tx = await sendTransaction(connection, wallet, instructions, [...signers]); @@ -202,6 +201,13 @@ export const borrow = async ( const memory = createTempMemoryAccount(instructions, wallet.publicKey, signers, LENDING_PROGRAM_ID); + instructions.push( + accrueInterestInstruction( + depositReserve.pubkey, + borrowReserve.pubkey, + ) + ); + // borrow instructions.push( borrowInstruction( diff --git a/src/actions/deposit.tsx b/src/actions/deposit.tsx index 454f3a2..f748fc4 100644 --- a/src/actions/deposit.tsx +++ b/src/actions/deposit.tsx @@ -7,6 +7,7 @@ import { import { sendTransaction } from "../contexts/connection"; import { notify } from "../utils/notifications"; import { + accrueInterestInstruction, depositInstruction, initReserveInstruction, LendingReserve, @@ -85,6 +86,12 @@ export const deposit = async ( } if (isInitalized) { + instructions.push( + accrueInterestInstruction( + reserveAddress, + ) + ); + // deposit instructions.push( depositInstruction( diff --git a/src/actions/liquidate.tsx b/src/actions/liquidate.tsx index d9f82c1..f76acff 100644 --- a/src/actions/liquidate.tsx +++ b/src/actions/liquidate.tsx @@ -6,7 +6,7 @@ import { } from "@solana/web3.js"; import { sendTransaction } from "../contexts/connection"; import { notify } from "../utils/notifications"; -import { LendingReserve } from "./../models/lending/reserve"; +import { accrueInterestInstruction, LendingReserve } from "./../models/lending/reserve"; import { liquidateInstruction } from "./../models/lending/liquidate"; import { AccountLayout } from "@solana/spl-token"; import { LENDING_PROGRAM_ID } from "../utils/ids"; @@ -92,6 +92,13 @@ export const liquidate = async ( const memory = createTempMemoryAccount(instructions, wallet.publicKey, signers, LENDING_PROGRAM_ID); + instructions.push( + accrueInterestInstruction( + repayReserve.pubkey, + withdrawReserve.pubkey, + ) + ); + instructions.push( liquidateInstruction( amountLamports, diff --git a/src/actions/repay.tsx b/src/actions/repay.tsx index e4365d6..9450715 100644 --- a/src/actions/repay.tsx +++ b/src/actions/repay.tsx @@ -6,7 +6,7 @@ import { } from "@solana/web3.js"; import { sendTransaction } from "../contexts/connection"; import { notify } from "../utils/notifications"; -import { LendingReserve } from "./../models/lending/reserve"; +import { accrueInterestInstruction, LendingReserve } from "./../models/lending/reserve"; import { repayInstruction } from "./../models/lending/repay"; import { AccountLayout, Token, NATIVE_MINT } from "@solana/spl-token"; import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../utils/ids"; @@ -87,8 +87,13 @@ export const repay = async ( transferAuthority.publicKey, ); - // TODO: add obligation - + instructions.push( + accrueInterestInstruction( + repayReserve.pubkey, + withdrawReserve.pubkey, + ) + ); + instructions.push( repayInstruction( repayAmount, diff --git a/src/actions/withdraw.tsx b/src/actions/withdraw.tsx index 2e3455c..b9b1726 100644 --- a/src/actions/withdraw.tsx +++ b/src/actions/withdraw.tsx @@ -6,7 +6,7 @@ import { } from "@solana/web3.js"; import { sendTransaction } from "../contexts/connection"; import { notify } from "../utils/notifications"; -import { LendingReserve, withdrawInstruction } from "./../models/lending"; +import { accrueInterestInstruction, LendingReserve, withdrawInstruction } from "./../models/lending"; import { AccountLayout } from "@solana/spl-token"; import { LENDING_PROGRAM_ID } from "../utils/ids"; import { findOrCreateAccountByMint } from "./account"; @@ -59,6 +59,12 @@ export const withdraw = async ( signers ); + instructions.push( + accrueInterestInstruction( + reserveAddress + ) + ); + instructions.push( withdrawInstruction( amountLamports, diff --git a/src/models/lending/reserve.ts b/src/models/lending/reserve.ts index 4bf053e..eb4c66f 100644 --- a/src/models/lending/reserve.ts +++ b/src/models/lending/reserve.ts @@ -205,7 +205,7 @@ export const initReserveInstruction = ( }; export const accrueInterestInstruction = ( - reserveAccount: PublicKey[], + ...reserveAccount: PublicKey[] ): TransactionInstruction => { const dataLayout = BufferLayout.struct([ BufferLayout.u8('instruction'), From f3a5b4bc2af7608c748731c6b3f0d89a70d8bf5a Mon Sep 17 00:00:00 2001 From: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com> Date: Fri, 22 Jan 2021 23:29:01 -0600 Subject: [PATCH 6/7] feat: switch to use bbo. resolves #42 --- README.md | 2 +- src/actions/account.ts | 75 ++++- src/actions/borrow.tsx | 136 +++++---- src/actions/deposit.tsx | 35 ++- src/actions/liquidate.tsx | 60 ++-- src/actions/repay.tsx | 62 ++-- src/actions/withdraw.tsx | 51 ++-- src/components/BarChartStatistic/index.tsx | 65 +++-- src/components/BorrowInput/index.tsx | 4 +- src/components/CollateralInput/index.tsx | 121 +++++--- src/components/CollateralSelector/index.tsx | 58 ++-- src/components/ConnectButton/index.tsx | 6 +- src/components/Input/numeric.tsx | 26 +- src/components/Layout/index.tsx | 173 +++++++----- src/components/LiquidateInput/index.tsx | 56 ++-- src/components/PoolPrice/index.tsx | 45 +-- src/components/ReserveStatus/index.tsx | 63 +++-- .../ReserveUtilizationChart/index.tsx | 11 +- src/components/SupplyOverview/index.tsx | 30 +- src/components/TokenDisplay/index.tsx | 30 +- src/components/UserLendingCard/index.tsx | 56 +++- src/components/WithdrawInput/index.tsx | 11 +- src/constants/labels.ts | 46 +-- src/constants/style.tsx | 2 +- src/contexts/accounts.tsx | 145 +++++++--- src/contexts/connection.tsx | 105 ++++--- src/contexts/lending.tsx | 107 ++++--- src/contexts/market.tsx | 264 +++++++++++++----- src/hooks/useBorrowedAmount.ts | 22 +- src/hooks/useBorrowingPower.ts | 36 ++- src/hooks/useCollateralBalance.ts | 31 +- src/hooks/useEnrichedLendingObligations.ts | 33 ++- src/hooks/useLendingReserves.ts | 3 +- src/hooks/useUserBalance.ts | 20 +- src/hooks/useUserDeposits.ts | 33 ++- src/hooks/useUserObligationByReserve.ts | 15 +- src/hooks/useUserObligations.ts | 10 +- src/index.tsx | 2 +- src/manifest.json | 3 +- src/models/account.ts | 17 +- src/models/airdrops.ts | 2 +- src/models/index.ts | 10 +- src/models/lending/borrow.ts | 40 +-- src/models/lending/deposit.ts | 24 +- src/models/lending/liquidate.ts | 21 +- src/models/lending/market.ts | 8 +- src/models/lending/obligation.ts | 25 +- src/models/lending/repay.ts | 23 +- src/models/lending/reserve.ts | 193 +++++++------ src/models/lending/withdraw.ts | 23 +- src/models/pool.ts | 4 +- src/models/tokenSwap.ts | 128 +++++---- src/routes.tsx | 83 ++++-- src/utils/eventEmitter.ts | 13 +- src/utils/ids.ts | 42 +-- src/utils/pools.ts | 137 ++++++--- src/views/borrow/index.tsx | 2 +- src/views/borrow/item.tsx | 35 ++- src/views/borrowReserve/index.tsx | 20 +- src/views/dashboard/deposit/index.tsx | 46 +-- src/views/dashboard/deposit/item.tsx | 50 ++-- src/views/dashboard/index.tsx | 54 ++-- src/views/dashboard/obligation/index.tsx | 19 +- src/views/dashboard/obligation/item.tsx | 78 +++--- src/views/deposit/view/index.tsx | 2 +- src/views/deposit/view/item.tsx | 28 +- src/views/home/index.tsx | 44 +-- src/views/home/item.tsx | 20 +- src/views/liquidate/index.tsx | 170 +++++------ src/views/liquidate/item.tsx | 22 +- src/views/liquidateReserve/index.tsx | 4 +- src/views/margin/index.tsx | 16 +- src/views/margin/item.tsx | 41 +-- src/views/margin/newPosition/Breakdown.tsx | 79 ++++-- src/views/margin/newPosition/GainsChart.tsx | 107 ++++--- .../margin/newPosition/NewPositionForm.tsx | 144 +++++++--- src/views/margin/newPosition/PoolHealth.tsx | 14 +- src/views/margin/newPosition/index.tsx | 33 ++- src/views/margin/newPosition/interfaces.tsx | 4 +- src/views/margin/newPosition/leverage.ts | 38 ++- src/views/margin/newPosition/utils.ts | 16 +- src/views/repayReserve/index.tsx | 20 +- src/views/reserve/index.tsx | 4 +- src/wdyr.ts | 8 +- 84 files changed, 2512 insertions(+), 1452 deletions(-) diff --git a/README.md b/README.md index d2d4c24..c2780eb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ ## ⚠️ Warning - + Any content produced by Solana, or developer resources that Solana provides, are for educational and inspiration purposes only. Solana does not encourage, induce or sanction the deployment of any such applications in violation of applicable laws or regulations. diff --git a/src/actions/account.ts b/src/actions/account.ts index 7e6e15c..daf99b7 100644 --- a/src/actions/account.ts +++ b/src/actions/account.ts @@ -1,8 +1,17 @@ -import { AccountLayout, MintLayout, Token } from '@solana/spl-token'; -import { Account, PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js'; -import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT } from '../utils/ids'; -import { LendingObligationLayout, TokenAccount } from '../models'; -import { cache, TokenAccountParser } from './../contexts/accounts'; +import { AccountLayout, MintLayout, Token } from "@solana/spl-token"; +import { + Account, + PublicKey, + SystemProgram, + TransactionInstruction, +} from "@solana/web3.js"; +import { + LENDING_PROGRAM_ID, + TOKEN_PROGRAM_ID, + WRAPPED_SOL_MINT, +} from "../utils/ids"; +import { LendingObligationLayout, TokenAccount } from "../models"; +import { cache, TokenAccountParser } from "./../contexts/accounts"; export function ensureSplAccount( instructions: TransactionInstruction[], @@ -16,11 +25,31 @@ export function ensureSplAccount( return toCheck.pubkey; } - const account = createUninitializedAccount(instructions, payer, amount, signers); + const account = createUninitializedAccount( + instructions, + payer, + amount, + signers + ); - instructions.push(Token.createInitAccountInstruction(TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT, account, payer)); + instructions.push( + Token.createInitAccountInstruction( + TOKEN_PROGRAM_ID, + WRAPPED_SOL_MINT, + account, + payer + ) + ); - cleanupInstructions.push(Token.createCloseAccountInstruction(TOKEN_PROGRAM_ID, account, payer, payer, [])); + cleanupInstructions.push( + Token.createCloseAccountInstruction( + TOKEN_PROGRAM_ID, + account, + payer, + payer, + [] + ) + ); return account; } @@ -125,9 +154,16 @@ export function createTokenAccount( owner: PublicKey, signers: Account[] ) { - const account = createUninitializedAccount(instructions, payer, accountRentExempt, signers); + const account = createUninitializedAccount( + instructions, + payer, + accountRentExempt, + signers + ); - instructions.push(Token.createInitAccountInstruction(TOKEN_PROGRAM_ID, mint, account, owner)); + instructions.push( + Token.createInitAccountInstruction(TOKEN_PROGRAM_ID, mint, account, owner) + ); return account; } @@ -161,10 +197,25 @@ export function findOrCreateAccountByMint( toAccount = account.pubkey; } else { // creating depositor pool account - toAccount = createTokenAccount(instructions, payer, accountRentExempt, mint, owner, signers); + toAccount = createTokenAccount( + instructions, + payer, + accountRentExempt, + mint, + owner, + signers + ); if (isWrappedSol) { - cleanupInstructions.push(Token.createCloseAccountInstruction(TOKEN_PROGRAM_ID, toAccount, payer, payer, [])); + cleanupInstructions.push( + Token.createCloseAccountInstruction( + TOKEN_PROGRAM_ID, + toAccount, + payer, + payer, + [] + ) + ); } } diff --git a/src/actions/borrow.tsx b/src/actions/borrow.tsx index a48554e..f6dd589 100644 --- a/src/actions/borrow.tsx +++ b/src/actions/borrow.tsx @@ -6,7 +6,10 @@ import { } from "@solana/web3.js"; import { sendTransaction } from "../contexts/connection"; import { notify } from "../utils/notifications"; -import { accrueInterestInstruction, LendingReserve } from "./../models/lending/reserve"; +import { + accrueInterestInstruction, + LendingReserve, +} from "./../models/lending/reserve"; import { AccountLayout, MintInfo, MintLayout } from "@solana/spl-token"; import { LENDING_PROGRAM_ID, LEND_HOST_FEE_ADDRESS } from "../utils/ids"; import { @@ -16,8 +19,8 @@ import { createUninitializedObligation, ensureSplAccount, findOrCreateAccountByMint, -} from './account'; -import { cache, MintParser, ParsedAccount } from '../contexts/accounts'; +} from "./account"; +import { cache, MintParser, ParsedAccount } from "../contexts/accounts"; import { TokenAccount, LendingObligationLayout, @@ -47,9 +50,9 @@ export const borrow = async ( obligationAccount?: PublicKey ) => { notify({ - message: 'Borrowing funds...', - description: 'Please review transactions to approve.', - type: 'warn', + message: "Borrowing funds...", + description: "Please review transactions to approve.", + type: "warn", }); let signers: Account[] = []; @@ -61,29 +64,38 @@ export const borrow = async ( LENDING_PROGRAM_ID ); - const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span); + const accountRentExempt = await connection.getMinimumBalanceForRentExemption( + AccountLayout.span + ); const obligation = existingObligation ? existingObligation.pubkey : createUninitializedObligation( - instructions, - wallet.publicKey, - await connection.getMinimumBalanceForRentExemption(LendingObligationLayout.span), - signers - ); + instructions, + wallet.publicKey, + await connection.getMinimumBalanceForRentExemption( + LendingObligationLayout.span + ), + signers + ); const obligationMint = existingObligation ? existingObligation.info.tokenMint : createUninitializedMint( - instructions, - wallet.publicKey, - await connection.getMinimumBalanceForRentExemption(MintLayout.span), - signers - ); + instructions, + wallet.publicKey, + await connection.getMinimumBalanceForRentExemption(MintLayout.span), + signers + ); const obligationTokenOutput = obligationAccount ? obligationAccount - : createUninitializedAccount(instructions, wallet.publicKey, accountRentExempt, signers); + : createUninitializedAccount( + instructions, + wallet.publicKey, + accountRentExempt, + signers + ); let toAccount = await findOrCreateAccountByMint( wallet.publicKey, @@ -105,39 +117,41 @@ export const borrow = async ( obligationTokenOutput, wallet.publicKey, depositReserve.info.lendingMarket, - authority, + authority ) ); } // Creates host fee account if it doesn't exsist let hostFeeReceiver = LEND_HOST_FEE_ADDRESS - ? findOrCreateAccountByMint( - wallet.publicKey, - LEND_HOST_FEE_ADDRESS, - instructions, - cleanupInstructions, - accountRentExempt, - depositReserve.info.collateralMint, - signers - ) - : undefined; + ? findOrCreateAccountByMint( + wallet.publicKey, + LEND_HOST_FEE_ADDRESS, + instructions, + cleanupInstructions, + accountRentExempt, + depositReserve.info.collateralMint, + signers + ) + : undefined; if (instructions.length > 0) { // create all accounts in one transaction - let tx = await sendTransaction(connection, wallet, instructions, [...signers]); + let tx = await sendTransaction(connection, wallet, instructions, [ + ...signers, + ]); notify({ - message: 'Obligation accounts created', + message: "Obligation accounts created", description: `Transaction ${tx}`, - type: 'success', + type: "success", }); } notify({ - message: 'Borrowing funds...', - description: 'Please review transactions to approve.', - type: 'warn', + message: "Borrowing funds...", + description: "Please review transactions to approve.", + type: "warn", }); signers = []; @@ -153,15 +167,19 @@ export const borrow = async ( fromLamports = approvedAmount - accountRentExempt; - const mint = (await cache.query(connection, borrowReserve.info.liquidityMint, MintParser)) as ParsedAccount< - MintInfo - >; + const mint = (await cache.query( + connection, + borrowReserve.info.liquidityMint, + MintParser + )) as ParsedAccount; amountLamports = toLamports(amount, mint?.info); } else if (amountType === BorrowAmountType.CollateralDepositAmount) { - const mint = (await cache.query(connection, depositReserve.info.collateralMint, MintParser)) as ParsedAccount< - MintInfo - >; + const mint = (await cache.query( + connection, + depositReserve.info.collateralMint, + MintParser + )) as ParsedAccount; amountLamports = toLamports(amount, mint?.info); fromLamports = amountLamports; } @@ -194,18 +212,24 @@ export const borrow = async ( 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) + const market = cache.get(depositReserve.info.lendingMarket) as ParsedAccount< + LendingMarket + >; + 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); + const memory = createTempMemoryAccount( + instructions, + wallet.publicKey, + signers, + LENDING_PROGRAM_ID + ); instructions.push( - accrueInterestInstruction( - depositReserve.pubkey, - borrowReserve.pubkey, - ) + accrueInterestInstruction(depositReserve.pubkey, borrowReserve.pubkey) ); // borrow @@ -235,19 +259,25 @@ export const borrow = async ( memory, - hostFeeReceiver, + hostFeeReceiver ) ); try { - let tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), signers, true); + let tx = await sendTransaction( + connection, + wallet, + instructions.concat(cleanupInstructions), + signers, + true + ); notify({ - message: 'Funds borrowed.', - type: 'success', + message: "Funds borrowed.", + type: "success", description: `Transaction - ${tx}`, }); } catch (ex) { - console.error(ex) + console.error(ex); throw new Error(); } }; diff --git a/src/actions/deposit.tsx b/src/actions/deposit.tsx index f748fc4..a1a700a 100644 --- a/src/actions/deposit.tsx +++ b/src/actions/deposit.tsx @@ -30,9 +30,9 @@ export const deposit = async ( wallet: any ) => { notify({ - message: 'Depositing funds...', - description: 'Please review transactions to approve.', - type: 'warn', + message: "Depositing funds...", + description: "Please review transactions to approve.", + type: "warn", }); const isInitalized = true; // TODO: finish reserve init @@ -42,7 +42,9 @@ export const deposit = async ( const instructions: TransactionInstruction[] = []; const cleanupInstructions: TransactionInstruction[] = []; - const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span); + const accountRentExempt = await connection.getMinimumBalanceForRentExemption( + AccountLayout.span + ); const [authority] = await PublicKey.findProgramAddress( [reserve.lendingMarket.toBuffer()], // which account should be authority @@ -82,15 +84,16 @@ export const deposit = async ( signers ); } else { - toAccount = createUninitializedAccount(instructions, wallet.publicKey, accountRentExempt, signers); + toAccount = createUninitializedAccount( + instructions, + wallet.publicKey, + accountRentExempt, + signers + ); } if (isInitalized) { - instructions.push( - accrueInterestInstruction( - reserveAddress, - ) - ); + instructions.push(accrueInterestInstruction(reserveAddress)); // deposit instructions.push( @@ -129,11 +132,17 @@ export const deposit = async ( } try { - let tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), signers, true); + let tx = await sendTransaction( + connection, + wallet, + instructions.concat(cleanupInstructions), + signers, + true + ); notify({ - message: 'Funds deposited.', - type: 'success', + message: "Funds deposited.", + type: "success", description: `Transaction - ${tx}`, }); } catch { diff --git a/src/actions/liquidate.tsx b/src/actions/liquidate.tsx index f76acff..b52fa18 100644 --- a/src/actions/liquidate.tsx +++ b/src/actions/liquidate.tsx @@ -6,12 +6,24 @@ import { } from "@solana/web3.js"; import { sendTransaction } from "../contexts/connection"; import { notify } from "../utils/notifications"; -import { accrueInterestInstruction, LendingReserve } from "./../models/lending/reserve"; +import { + accrueInterestInstruction, + LendingReserve, +} from "./../models/lending/reserve"; import { liquidateInstruction } from "./../models/lending/liquidate"; import { AccountLayout } from "@solana/spl-token"; import { LENDING_PROGRAM_ID } from "../utils/ids"; -import { createTempMemoryAccount, ensureSplAccount, findOrCreateAccountByMint } from "./account"; -import { approve, LendingMarket, LendingObligation, TokenAccount } from "../models"; +import { + createTempMemoryAccount, + ensureSplAccount, + findOrCreateAccountByMint, +} from "./account"; +import { + approve, + LendingMarket, + LendingObligation, + TokenAccount, +} from "../models"; import { cache, ParsedAccount } from "../contexts/accounts"; export const liquidate = async ( @@ -28,9 +40,9 @@ export const liquidate = async ( withdrawReserve: ParsedAccount ) => { notify({ - message: 'Repaying funds...', - description: 'Please review transactions to approve.', - type: 'warn', + message: "Repaying funds...", + description: "Please review transactions to approve.", + type: "warn", }); // user from account @@ -38,7 +50,9 @@ export const liquidate = async ( const instructions: TransactionInstruction[] = []; const cleanupInstructions: TransactionInstruction[] = []; - const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span); + const accountRentExempt = await connection.getMinimumBalanceForRentExemption( + AccountLayout.span + ); const [authority] = await PublicKey.findProgramAddress( [repayReserve.info.lendingMarket.toBuffer()], @@ -84,19 +98,25 @@ export const liquidate = async ( throw new Error(`Dex market doesn't exist.`); } - const market = cache.get(withdrawReserve.info.lendingMarket) as ParsedAccount; + const market = cache.get(withdrawReserve.info.lendingMarket) as ParsedAccount< + LendingMarket + >; - const dexOrderBookSide = market.info.quoteMint.equals(repayReserve.info.liquidityMint) + const dexOrderBookSide = market.info.quoteMint.equals( + repayReserve.info.liquidityMint + ) ? dexMarket?.info.asks : dexMarket?.info.bids; - const memory = createTempMemoryAccount(instructions, wallet.publicKey, signers, LENDING_PROGRAM_ID); + const memory = createTempMemoryAccount( + instructions, + wallet.publicKey, + signers, + LENDING_PROGRAM_ID + ); instructions.push( - accrueInterestInstruction( - repayReserve.pubkey, - withdrawReserve.pubkey, - ) + accrueInterestInstruction(repayReserve.pubkey, withdrawReserve.pubkey) ); instructions.push( @@ -118,11 +138,17 @@ export const liquidate = async ( ) ); - let tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), signers, true); + let tx = await sendTransaction( + connection, + wallet, + instructions.concat(cleanupInstructions), + signers, + true + ); notify({ - message: 'Funds liquidated.', - type: 'success', + message: "Funds liquidated.", + type: "success", description: `Transaction - ${tx}`, }); }; diff --git a/src/actions/repay.tsx b/src/actions/repay.tsx index 9450715..1d5d80b 100644 --- a/src/actions/repay.tsx +++ b/src/actions/repay.tsx @@ -6,7 +6,10 @@ import { } from "@solana/web3.js"; import { sendTransaction } from "../contexts/connection"; import { notify } from "../utils/notifications"; -import { accrueInterestInstruction, LendingReserve } from "./../models/lending/reserve"; +import { + accrueInterestInstruction, + LendingReserve, +} from "./../models/lending/reserve"; import { repayInstruction } from "./../models/lending/repay"; import { AccountLayout, Token, NATIVE_MINT } from "@solana/spl-token"; import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../utils/ids"; @@ -31,9 +34,9 @@ export const repay = async ( wallet: any ) => { notify({ - message: 'Repaying funds...', - description: 'Please review transactions to approve.', - type: 'warn', + message: "Repaying funds...", + description: "Please review transactions to approve.", + type: "warn", }); // user from account @@ -41,7 +44,9 @@ export const repay = async ( const instructions: TransactionInstruction[] = []; const cleanupInstructions: TransactionInstruction[] = []; - const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span); + const accountRentExempt = await connection.getMinimumBalanceForRentExemption( + AccountLayout.span + ); const [authority] = await PublicKey.findProgramAddress( [repayReserve.info.lendingMarket.toBuffer()], @@ -49,9 +54,27 @@ export const repay = async ( ); let fromAccount = from.pubkey; - if (wallet.publicKey.equals(fromAccount) && repayReserve.info.liquidityMint.equals(NATIVE_MINT)) { - fromAccount = createTokenAccount(instructions, wallet.publicKey, accountRentExempt + repayAmount, NATIVE_MINT, wallet.publicKey, signers); - cleanupInstructions.push(Token.createCloseAccountInstruction(TOKEN_PROGRAM_ID, fromAccount, wallet.publicKey, wallet.publicKey, [])); + if ( + wallet.publicKey.equals(fromAccount) && + repayReserve.info.liquidityMint.equals(NATIVE_MINT) + ) { + fromAccount = createTokenAccount( + instructions, + wallet.publicKey, + accountRentExempt + repayAmount, + NATIVE_MINT, + wallet.publicKey, + signers + ); + cleanupInstructions.push( + Token.createCloseAccountInstruction( + TOKEN_PROGRAM_ID, + fromAccount, + wallet.publicKey, + wallet.publicKey, + [] + ) + ); } // create approval for transfer transactions @@ -84,16 +107,13 @@ export const repay = async ( obligationToken.info.amount.toNumber(), // reuse transfer authority - transferAuthority.publicKey, + transferAuthority.publicKey ); instructions.push( - accrueInterestInstruction( - repayReserve.pubkey, - withdrawReserve.pubkey, - ) + accrueInterestInstruction(repayReserve.pubkey, withdrawReserve.pubkey) ); - + instructions.push( repayInstruction( repayAmount, @@ -108,15 +128,21 @@ export const repay = async ( obligationToken.pubkey, repayReserve.info.lendingMarket, authority, - transferAuthority.publicKey, + transferAuthority.publicKey ) ); - let tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), signers, true); + let tx = await sendTransaction( + connection, + wallet, + instructions.concat(cleanupInstructions), + signers, + true + ); notify({ - message: 'Funds repaid.', - type: 'success', + message: "Funds repaid.", + type: "success", description: `Transaction - ${tx}`, }); }; diff --git a/src/actions/withdraw.tsx b/src/actions/withdraw.tsx index b9b1726..4ee4745 100644 --- a/src/actions/withdraw.tsx +++ b/src/actions/withdraw.tsx @@ -6,7 +6,11 @@ import { } from "@solana/web3.js"; import { sendTransaction } from "../contexts/connection"; import { notify } from "../utils/notifications"; -import { accrueInterestInstruction, LendingReserve, withdrawInstruction } from "./../models/lending"; +import { + accrueInterestInstruction, + LendingReserve, + withdrawInstruction, +} from "./../models/lending"; import { AccountLayout } from "@solana/spl-token"; import { LENDING_PROGRAM_ID } from "../utils/ids"; import { findOrCreateAccountByMint } from "./account"; @@ -21,9 +25,9 @@ export const withdraw = async ( wallet: any ) => { notify({ - message: 'Withdrawing funds...', - description: 'Please review transactions to approve.', - type: 'warn', + message: "Withdrawing funds...", + description: "Please review transactions to approve.", + type: "warn", }); // user from account @@ -31,19 +35,24 @@ export const withdraw = async ( const instructions: TransactionInstruction[] = []; const cleanupInstructions: TransactionInstruction[] = []; - const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span); + const accountRentExempt = await connection.getMinimumBalanceForRentExemption( + AccountLayout.span + ); - const [authority] = await PublicKey.findProgramAddress([reserve.lendingMarket.toBuffer()], LENDING_PROGRAM_ID); + const [authority] = await PublicKey.findProgramAddress( + [reserve.lendingMarket.toBuffer()], + LENDING_PROGRAM_ID + ); const fromAccount = from.pubkey; // create approval for transfer transactions const transferAuthority = approve( - instructions, - cleanupInstructions, - fromAccount, - wallet.publicKey, - amountLamports + instructions, + cleanupInstructions, + fromAccount, + wallet.publicKey, + amountLamports ); signers.push(transferAuthority); @@ -59,11 +68,7 @@ export const withdraw = async ( signers ); - instructions.push( - accrueInterestInstruction( - reserveAddress - ) - ); + instructions.push(accrueInterestInstruction(reserveAddress)); instructions.push( withdrawInstruction( @@ -75,16 +80,22 @@ export const withdraw = async ( reserve.liquiditySupply, reserve.lendingMarket, authority, - transferAuthority.publicKey, + transferAuthority.publicKey ) ); try { - let tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), signers, true); + let tx = await sendTransaction( + connection, + wallet, + instructions.concat(cleanupInstructions), + signers, + true + ); notify({ - message: 'Funds deposited.', - type: 'success', + message: "Funds deposited.", + type: "success", description: `Transaction - ${tx}`, }); } catch { diff --git a/src/components/BarChartStatistic/index.tsx b/src/components/BarChartStatistic/index.tsx index 3b3e336..fd7ab6b 100644 --- a/src/components/BarChartStatistic/index.tsx +++ b/src/components/BarChartStatistic/index.tsx @@ -1,7 +1,7 @@ import { Statistic } from "antd"; -import React, { } from "react"; +import React from "react"; -export const BarChartStatistic = (props: { +export const BarChartStatistic = (props: { items: T[]; title?: string; name: (item: T) => string; @@ -9,34 +9,47 @@ 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 ( - -
- {props.items.map((item, i) => -
( +
+ {props.items.map((item, i) => ( +
- {props.name(item)} -
)} -
} - > - + width: `${100 * props.getPct(item)}%`, + backgroundColor: + (props.color && props.color(item)) || + colors[i % props.items.length], + }} + > + {props.name(item)} +
+ ))} +
+ )} + >
); }; diff --git a/src/components/BorrowInput/index.tsx b/src/components/BorrowInput/index.tsx index f0c6740..dbdd27a 100644 --- a/src/components/BorrowInput/index.tsx +++ b/src/components/BorrowInput/index.tsx @@ -157,7 +157,9 @@ export const BorrowInput = (props: { loading={pendingTx} disabled={fromAccounts.length === 0} > - {fromAccounts.length === 0 ? LABELS.NO_DEPOSITS : LABELS.BORROW_ACTION} + {fromAccounts.length === 0 + ? LABELS.NO_DEPOSITS + : LABELS.BORROW_ACTION} diff --git a/src/components/CollateralInput/index.tsx b/src/components/CollateralInput/index.tsx index 059c1b8..a29ed4d 100644 --- a/src/components/CollateralInput/index.tsx +++ b/src/components/CollateralInput/index.tsx @@ -1,14 +1,18 @@ -import React, { useEffect, useState } from 'react'; -import { cache, ParsedAccount } from '../../contexts/accounts'; -import { useConnectionConfig } from '../../contexts/connection'; -import { useLendingReserves, useUserDeposits } from '../../hooks'; -import { LendingReserve, LendingMarket, LendingReserveParser } from '../../models'; -import { getTokenName } from '../../utils/utils'; -import { Card, Select } from 'antd'; -import { TokenIcon } from '../TokenIcon'; -import { NumericInput } from '../Input/numeric'; -import './style.less'; -import { TokenDisplay } from '../TokenDisplay'; +import React, { useEffect, useState } from "react"; +import { cache, ParsedAccount } from "../../contexts/accounts"; +import { useConnectionConfig } from "../../contexts/connection"; +import { useLendingReserves, useUserDeposits } from "../../hooks"; +import { + LendingReserve, + LendingMarket, + LendingReserveParser, +} from "../../models"; +import { getTokenName } from "../../utils/utils"; +import { Card, Select } from "antd"; +import { TokenIcon } from "../TokenIcon"; +import { NumericInput } from "../Input/numeric"; +import "./style.less"; +import { TokenDisplay } from "../TokenDisplay"; const { Option } = Select; @@ -30,36 +34,49 @@ export default function CollateralInput(props: { const { tokenMap } = useConnectionConfig(); const [collateralReserve, setCollateralReserve] = useState(); const [balance, setBalance] = useState(0); - const [lastAmount, setLastAmount] = useState(''); + const [lastAmount, setLastAmount] = useState(""); const userDeposits = useUserDeposits(); useEffect(() => { - const id: string = cache.byParser(LendingReserveParser).find((acc) => acc === collateralReserve) || ''; + const id: string = + cache + .byParser(LendingReserveParser) + .find((acc) => acc === collateralReserve) || ""; 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) => + u.reserve.info.liquidityMint.toBase58() === + parser.info.liquidityMint.toBase58() ); if (collateralDeposit) setBalance(collateralDeposit.info.amount); else setBalance(0); } }, [collateralReserve, userDeposits]); - const market = cache.get(props.reserve.lendingMarket) as ParsedAccount; + const market = cache.get(props.reserve.lendingMarket) as ParsedAccount< + LendingMarket + >; if (!market) return null; - const onlyQuoteAllowed = !props.reserve?.liquidityMint?.equals(market?.info?.quoteMint); + const onlyQuoteAllowed = !props.reserve?.liquidityMint?.equals( + market?.info?.quoteMint + ); const renderReserveAccounts = reserveAccounts .filter((reserve) => reserve.info !== props.reserve) - .filter((reserve) => !onlyQuoteAllowed || reserve.info.liquidityMint.equals(market.info.quoteMint)) + .filter( + (reserve) => + !onlyQuoteAllowed || + reserve.info.liquidityMint.equals(market.info.quoteMint) + ) .map((reserve) => { const mint = reserve.info.liquidityMint.toBase58(); const address = reserve.pubkey.toBase58(); const name = getTokenName(tokenMap, mint); return (