From 097dc95f5f96a25dd0af163a38e52ff32ca97149 Mon Sep 17 00:00:00 2001 From: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com> Date: Thu, 26 Nov 2020 00:04:26 -0600 Subject: [PATCH] feat: reuse obligations --- README.md | 10 ++- src/actions/borrow.tsx | 84 +++++++++++--------- src/components/BorrowInput/index.tsx | 23 ++++-- src/components/SideReserveOverview/index.tsx | 1 - src/constants/labels.ts | 4 +- src/hooks/useUserBalance.ts | 2 +- src/models/lending/borrow.ts | 1 - src/views/dashboard/depositItem.tsx | 38 ++++----- src/views/dashboard/index.tsx | 2 +- src/views/dashboard/obligationItem.tsx | 35 ++++---- src/views/dashboard/style.less | 10 ++- 11 files changed, 123 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index c05edcb..d3908ad 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,14 @@ Any content produced by Solana, or developer resources that Solana provides, are ## TODO -- [] Calculate deposit APY and borrow APY for home page +- [x] Calculate deposit APY and borrow APY for home page - [] Finish Reserve overview page (chart, and borrows information) -- [] Create Dashboard page +- [x] Create Dashboard page - [] Deposit view calculate APY and health factor - [x] Format total Borrows - [x] Add repay view - [] Add liquidate view -- [] Borrow view calculate available to you and borrow APY +- [x] Borrow view calculate available to you and borrow APY - [] Facuet add USDC that is using sol airdrop and USDC reserve to give user USDC - [] Borrow - Convert target ccy to collateral on oposite side - [] Borrow - liquidity token wrapped SOL should be unwrapped ... @@ -22,3 +22,7 @@ Any content produced by Solana, or developer resources that Solana provides, are - [] Repay from reserve (add selection for obligation/loan) - [] Add support for token names in URL in addition to reserve address +# TOP for tomorrow + +* subscribe to all dex markets that are used by lending reserves +* finish reserve overivew diff --git a/src/actions/borrow.tsx b/src/actions/borrow.tsx index 6f6db29..a504d0f 100644 --- a/src/actions/borrow.tsx +++ b/src/actions/borrow.tsx @@ -29,6 +29,9 @@ import { import { toLamports } from "../utils/utils"; export const borrow = async ( + connection: Connection, + wallet: any, + from: TokenAccount, amount: number, amountType: BorrowAmountType, @@ -37,10 +40,10 @@ export const borrow = async ( depositReserve: ParsedAccount, - exsistingObligation: ParsedAccount | undefined, + exsistingObligation?: ParsedAccount, + + obligationAccount?: PublicKey, - connection: Connection, - wallet: any ) => { notify({ message: "Borrowing funds...", @@ -56,28 +59,34 @@ export const borrow = async ( AccountLayout.span ); - const obligation = createUninitializedObligation( - instructions, - wallet.publicKey, - await connection.getMinimumBalanceForRentExemption( - LendingObligationLayout.span - ), - signers - ); + const obligation = exsistingObligation ? + exsistingObligation.pubkey : + createUninitializedObligation( + instructions, + wallet.publicKey, + await connection.getMinimumBalanceForRentExemption( + LendingObligationLayout.span + ), + signers + ); - const obligationMint = createUninitializedMint( - instructions, - wallet.publicKey, - await connection.getMinimumBalanceForRentExemption(MintLayout.span), - signers - ); + const obligationMint = exsistingObligation ? + exsistingObligation.info.tokenMint : + createUninitializedMint( + instructions, + wallet.publicKey, + await connection.getMinimumBalanceForRentExemption(MintLayout.span), + signers + ); - const obligationTokenOutput = createUninitializedAccount( - instructions, - wallet.publicKey, - accountRentExempt, - signers - ); + const obligationTokenOutput = obligationAccount ? + obligationAccount : + createUninitializedAccount( + instructions, + wallet.publicKey, + accountRentExempt, + signers + ); let toAccount = await findOrCreateAccountByMint( wallet.publicKey, @@ -89,23 +98,26 @@ export const borrow = async ( signers ); - // create all accounts in one transaction - let tx = await sendTransaction(connection, wallet, instructions, [ - ...signers, - ]); - - notify({ - message: "Obligation accounts created", - description: `Transaction ${tx}`, - type: "success", - }); + if (instructions.length > 0) { + // create all accounts in one transaction + let tx = await sendTransaction(connection, wallet, instructions, [ + ...signers, + ]); + notify({ + message: "Obligation accounts created", + description: `Transaction ${tx}`, + type: "success", + }); + } + notify({ message: "Adding Liquidity...", description: "Please review transactions to approve.", type: "warn", }); + signers = []; instructions = []; cleanupInstructions = []; @@ -115,11 +127,9 @@ export const borrow = async ( LENDING_PROGRAM_ID ); - - let amountLamports: number = 0; let fromLamports: number = 0; - if(amountType === BorrowAmountType.LiquidityBorrowAmount) { + if (amountType === BorrowAmountType.LiquidityBorrowAmount) { // approve max transfer // TODO: improve contrain by using dex market data const approvedAmount = from.info.amount.toNumber(); @@ -133,7 +143,7 @@ export const borrow = async ( )) as ParsedAccount; amountLamports = toLamports(amount, mint?.info); - } else if(amountType === BorrowAmountType.CollateralDepositAmount) { + } else if (amountType === BorrowAmountType.CollateralDepositAmount) { const mint = (await cache.query( connection, depositReserve.info.collateralMint, diff --git a/src/components/BorrowInput/index.tsx b/src/components/BorrowInput/index.tsx index a3551b3..7d260f3 100644 --- a/src/components/BorrowInput/index.tsx +++ b/src/components/BorrowInput/index.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useMemo, useState } from "react"; -import { useTokenName, useUserBalance } from "../../hooks"; +import { useTokenName, useUserBalance, useUserObligationByReserve } from "../../hooks"; import { BorrowAmountType, LendingReserve, LendingReserveParser } from "../../models"; import { TokenIcon } from "../TokenIcon"; import { Button, Card } from "antd"; @@ -8,7 +8,6 @@ import { NumericInput } from "../Input/numeric"; import { useConnection } from "../../contexts/connection"; import { useWallet } from "../../contexts/wallet"; import { borrow } from "../../actions"; -import { PublicKey } from "@solana/web3.js"; import { CollateralSelector } from "./../CollateralSelector"; import "./style.less"; import { LABELS } from "../../constants"; @@ -38,7 +37,8 @@ export const BorrowInput = (props: { const { accounts: fromAccounts } = useUserBalance( collateralReserve?.info.collateralMint ); - // const collateralBalance = useUserBalance(reserve?.collateralMint); + + const { userObligationsByReserve } = useUserObligationByReserve(borrowReserve.pubkey) const onBorrow = useCallback(() => { if (!collateralReserve) { @@ -46,15 +46,23 @@ export const BorrowInput = (props: { } borrow( + connection, + wallet, + fromAccounts[0], parseFloat(value), // TODO: switch to collateral when user is using slider - BorrowAmountType.LiquidityBorrowAmount, + BorrowAmountType.LiquidityBorrowAmount, borrowReserve, collateralReserve, - undefined, - connection, - wallet + + userObligationsByReserve.length > 0 ? + userObligationsByReserve[0].obligation : + undefined, + + userObligationsByReserve.length > 0 ? + userObligationsByReserve[0].userAccounts[0].pubkey : + undefined ); }, [ connection, @@ -63,6 +71,7 @@ export const BorrowInput = (props: { collateralReserve, borrowReserve, fromAccounts, + userObligationsByReserve, ]); const bodyStyle: React.CSSProperties = { diff --git a/src/components/SideReserveOverview/index.tsx b/src/components/SideReserveOverview/index.tsx index 45c9ba3..db5d4f4 100644 --- a/src/components/SideReserveOverview/index.tsx +++ b/src/components/SideReserveOverview/index.tsx @@ -5,7 +5,6 @@ import { TokenIcon } from "../../components/TokenIcon"; import { formatNumber, formatPct, fromLamports } from "../../utils/utils"; import { Card, Typography } from "antd"; import { ParsedAccount, useMint } from "../../contexts/accounts"; -import { PublicKey } from "@solana/web3.js"; import { Link } from "react-router-dom"; const { Text } = Typography; diff --git a/src/constants/labels.ts b/src/constants/labels.ts index f7ba836..b9f8d9d 100644 --- a/src/constants/labels.ts +++ b/src/constants/labels.ts @@ -22,7 +22,7 @@ export const LABELS = { BORROW_ACTION: "Borrow", TABLE_TITLE_ASSET: "Asset", TABLE_TITLE_LOAN_BALANCE: "Your loan balance", - TABLE_TITLE_DEPOSIT_BALANCE: "Your deposit balane", + TABLE_TITLE_DEPOSIT_BALANCE: "Your deposit balance", TABLE_TITLE_APY: "APY", TABLE_TITLE_APR: "APR", TABLE_TITLE_BORROW_APR: "Borrow APR", @@ -32,7 +32,7 @@ export const LABELS = { TABLE_TITLE_ACTION: "Action", TABLE_TITLE_MAX_BORROW: "Available fro you", DASHBOARD_TITLE_LOANS: "Loans", - DASHBOARD_TITLE_DEPOSITS: "Deposts", + DASHBOARD_TITLE_DEPOSITS: "Deposits", WITHDRAW_ACTION: "Withdraw", WITHDRAW_QUESTION: "How much would you like to withdraw?", }; diff --git a/src/hooks/useUserBalance.ts b/src/hooks/useUserBalance.ts index edc3a5e..7a07977 100644 --- a/src/hooks/useUserBalance.ts +++ b/src/hooks/useUserBalance.ts @@ -11,7 +11,7 @@ export function useUserBalance(mint?: PublicKey, account?: PublicKey) { return userAccounts .filter((acc) => mint?.equals(acc.info.mint) && (!account || account.equals(acc.pubkey))) .sort((a, b) => b.info.amount.sub(a.info.amount).toNumber()); - }, [userAccounts, mint]); + }, [userAccounts, mint, account]); const balanceLamports = useMemo(() => { return accounts.reduce( diff --git a/src/models/lending/borrow.ts b/src/models/lending/borrow.ts index 804338d..d254506 100644 --- a/src/models/lending/borrow.ts +++ b/src/models/lending/borrow.ts @@ -74,7 +74,6 @@ export const borrowInstruction = ( }, data ); - debugger; const keys = [ { pubkey: from, isSigner: false, isWritable: true }, diff --git a/src/views/dashboard/depositItem.tsx b/src/views/dashboard/depositItem.tsx index 40b5202..af4edbe 100644 --- a/src/views/dashboard/depositItem.tsx +++ b/src/views/dashboard/depositItem.tsx @@ -2,14 +2,12 @@ import React from "react"; import { useCollateralBalance, useTokenName, - useUserBalance, } from "../../hooks"; import { LendingReserve } from "../../models/lending"; import { TokenIcon } from "../../components/TokenIcon"; import { formatNumber } from "../../utils/utils"; import { Button, Card } from "antd"; import { Link } from "react-router-dom"; -import { PublicKey } from "@solana/web3.js"; import { TokenAccount } from "../../models"; import { ParsedAccount } from "../../contexts/accounts"; @@ -17,31 +15,35 @@ export const DepositItem = (props: { reserve: ParsedAccount; account: TokenAccount; }) => { - const account = props.account.info; const mintAddress = props.reserve.info.liquidityMint; const name = useTokenName(mintAddress); const { balance: collateralBalance } = useCollateralBalance(props.reserve.info, props.account.pubkey); return ( - - -
- - - {name} - -
- {formatNumber.format(collateralBalance)} {name} -
-
--
-
+ +
+ + + {name} + +
+ {formatNumber.format(collateralBalance)} {name} +
+
--
+
+ + + + -
+
-
- +
+ ); }; diff --git a/src/views/dashboard/index.tsx b/src/views/dashboard/index.tsx index 337026a..fad9ef4 100644 --- a/src/views/dashboard/index.tsx +++ b/src/views/dashboard/index.tsx @@ -8,7 +8,7 @@ import "./style.less"; export const DashboardView = () => { const { userObligations } = useUserObligations(); const { userDeposits } = useUserDeposits(); - + return (
diff --git a/src/views/dashboard/obligationItem.tsx b/src/views/dashboard/obligationItem.tsx index bdc8cee..a7f8ea9 100644 --- a/src/views/dashboard/obligationItem.tsx +++ b/src/views/dashboard/obligationItem.tsx @@ -26,24 +26,29 @@ export const ObligationItem = (props: { ); return ( - - -
- - - {name} - -
- {formatNumber.format(borrowAmount)} {name} -
-
--
-
+ +
+ + + {name} + +
+ {formatNumber.format(borrowAmount)} {name} +
+
--
+
+ + + + -
+
-
- +
+ ); }; diff --git a/src/views/dashboard/style.less b/src/views/dashboard/style.less index 93248e9..19fb8db 100644 --- a/src/views/dashboard/style.less +++ b/src/views/dashboard/style.less @@ -12,6 +12,10 @@ & > :first-child { flex: 80px } + + & > :last-child { + flex: 200px + } } .dashboard-header { @@ -26,6 +30,10 @@ text-align: left; flex: 80px } + + & > :last-child { + flex: 200px + } } .dashboard-container { @@ -43,7 +51,7 @@ flex: 50%; } -@media (max-width: 600px) { +@media (max-width: 700px) { .dashboard-right, .dashboard-left { flex: 100%; }