feat: reuse obligations

This commit is contained in:
bartosz-lipinski 2020-11-26 00:04:26 -06:00
parent 00db4555be
commit 097dc95f5f
11 changed files with 123 additions and 87 deletions

View File

@ -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

View File

@ -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<LendingReserve>,
exsistingObligation: ParsedAccount<LendingObligation> | undefined,
exsistingObligation?: ParsedAccount<LendingObligation>,
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<MintInfo>;
amountLamports = toLamports(amount, mint?.info);
} else if(amountType === BorrowAmountType.CollateralDepositAmount) {
} else if (amountType === BorrowAmountType.CollateralDepositAmount) {
const mint = (await cache.query(
connection,
depositReserve.info.collateralMint,

View File

@ -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 = {

View File

@ -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;

View File

@ -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?",
};

View File

@ -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(

View File

@ -74,7 +74,6 @@ export const borrowInstruction = (
},
data
);
debugger;
const keys = [
{ pubkey: from, isSigner: false, isWritable: true },

View File

@ -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<LendingReserve>;
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 (
<Link to={`/withdraw/${props.reserve.pubkey.toBase58()}`}>
<Card>
<div className="deposit-item">
<span style={{ display: "flex" }}>
<TokenIcon mintAddress={mintAddress} />
{name}
</span>
<div>
{formatNumber.format(collateralBalance)} {name}
</div>
<div>--</div>
<div>
<Card>
<div className="dashboard-item">
<span style={{ display: "flex" }}>
<TokenIcon mintAddress={mintAddress} />
{name}
</span>
<div>
{formatNumber.format(collateralBalance)} {name}
</div>
<div>--</div>
<div style={{ display: "flex", justifyContent: 'flex-end' }}>
<Link to={`/deposit/${props.reserve.pubkey.toBase58()}`}>
<Button>
<span>Deposit</span>
</Button>
</Link>
<Link to={`/withdraw/${props.reserve.pubkey.toBase58()}`}>
<Button>
<span>Withdraw</span>
</Button>
</div>
</Link>
</div>
</Card>
</Link>
</div>
</Card>
);
};

View File

@ -8,7 +8,7 @@ import "./style.less";
export const DashboardView = () => {
const { userObligations } = useUserObligations();
const { userDeposits } = useUserDeposits();
return (
<div className="dashboard-container">
<div className="dashboard-left">

View File

@ -26,24 +26,29 @@ export const ObligationItem = (props: {
);
return (
<Link to={`/repay/loan/${obligation.pubkey.toBase58()}`}>
<Card>
<div className="dashboard-item">
<span style={{ display: "flex" }}>
<TokenIcon mintAddress={borrowReserve?.info.liquidityMint} />
{name}
</span>
<div>
{formatNumber.format(borrowAmount)} {name}
</div>
<div>--</div>
<div>
<Card>
<div className="dashboard-item">
<span style={{ display: "flex" }}>
<TokenIcon mintAddress={borrowReserve?.info.liquidityMint} />
{name}
</span>
<div>
{formatNumber.format(borrowAmount)} {name}
</div>
<div>--</div>
<div style={{ display: "flex", justifyContent: 'flex-end' }}>
<Link to={`/borrow/${borrowReserve.pubkey.toBase58()}`}>
<Button>
<span>Borrow</span>
</Button>
</Link>
<Link to={`/repay/loan/${obligation.pubkey.toBase58()}`}>
<Button>
<span>Repay</span>
</Button>
</div>
</Link>
</div>
</Card>
</Link>
</div>
</Card>
);
};

View File

@ -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%;
}