feat: add collateral selection

This commit is contained in:
bartosz-lipinski 2020-11-20 09:24:39 -06:00
parent d63da050ad
commit 3554e8ce86
14 changed files with 126 additions and 128 deletions

View File

@ -1,17 +1,56 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models/lending";
import { useCollateralBalance, useLendingReserve, useLendingReserves, useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models";
import { TokenIcon } from "../TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button, Card } from "antd";
import { formatNumber, getTokenName } from "../../utils/utils";
import { Button, Card, Select } from "antd";
import { useParams } from "react-router-dom";
import { cache, useAccount } from "../../contexts/accounts";
import { cache, ParsedAccount, useAccount } from "../../contexts/accounts";
import { NumericInput } from "../Input/numeric";
import { useConnection } from "../../contexts/connection";
import { useConnection, useConnectionConfig } from "../../contexts/connection";
import { useWallet } from "../../contexts/wallet";
import { borrow } from '../../actions';
import { PublicKey } from "@solana/web3.js";
import './style.less';
import { Token } from "@solana/spl-token";
const { Option } = Select;
const CollateralSelector = (props: {
mint?: string,
onMintChange: (id: string) => void;
}) => {
const { reserveAccounts } = useLendingReserves();
const { tokenMap } = useConnectionConfig();
return <Select
size="large"
showSearch
style={{ minWidth: 120 }}
placeholder="Collateral"
value={props.mint}
onChange={(item) => {
if (props.onMintChange) {
props.onMintChange(item);
}
}}
filterOption={(input, option) =>
option?.name?.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{reserveAccounts.map(reserve => {
const mint = reserve.info.liquidityMint.toBase58();
const address = reserve.pubkey.toBase58();
const name = getTokenName(tokenMap, mint);
return <Option key={address} value={address} name={name} title={address}>
<div key={address} style={{ display: "flex", alignItems: "center" }}>
<TokenIcon mintAddress={mint} />
{name}
</div>
</Option>
})}
</Select>;
}
export const BorrowInput = (props: { className?: string, reserve: LendingReserve, address: PublicKey }) => {
const connection = useConnection();
@ -22,32 +61,43 @@ export const BorrowInput = (props: { className?: string, reserve: LendingReserve
const borrowReserve = props.reserve;
const borrowReserveAddress = props.address;
const [collateralReserve, setCollateralReserve] = useState<LendingReserve>();
const [collateralReserveMint, setCollateralReserveMint] = useState<string>();
const collateralReserveAddress = useMemo(() => {
return cache.byParser(LendingReserveParser)
.find(acc => cache.get(acc) === collateralReserve);
}, [collateralReserve])
const collateralReserve = useMemo(() => {
const id: string = cache.byParser(LendingReserveParser)
.find(acc => acc === collateralReserveMint) || '';
return cache.get(id) as ParsedAccount<LendingReserve>;
}, [collateralReserveMint])
const collateral = useCollateralBalance(collateralReserve?.info);
const name = useTokenName(borrowReserve?.liquidityMint);
const {
balance: tokenBalance,
accounts: fromAccounts
} = useUserBalance(collateralReserve?.liquidityMint);
const {
balance: tokenBalance,
accounts: fromAccounts
} = useUserBalance(collateralReserve?.info.collateralMint);
// const collateralBalance = useUserBalance(reserve?.collateralMint);
if(collateral) {
debugger;
}
const onBorrow = useCallback(() => {
if(!collateralReserve || !collateralReserveAddress) {
if (!collateralReserve) {
return;
}
debugger;
borrow(
fromAccounts[0],
parseFloat(value),
borrowReserve,
borrowReserveAddress,
collateralReserve,
new PublicKey(collateralReserveAddress),
collateralReserve.info,
collateralReserve.pubkey,
connection,
wallet);
}, [value, borrowReserve, fromAccounts, borrowReserveAddress]);
@ -83,6 +133,13 @@ export const BorrowInput = (props: { className?: string, reserve: LendingReserve
/>
<div>{name}</div>
</div>
<div className="borrow-input-title">
Select collateral account?
</div>
<CollateralSelector
mint={collateralReserveMint}
onMintChange={setCollateralReserveMint}
/>
<Button type="primary" onClick={onBorrow} disabled={fromAccounts.length === 0}>Borrow</Button>
</div>

View File

@ -1,15 +1,8 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance, useCollateralBalance } from './../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import React, { } from "react";
import { useTokenName, useUserBalance, useCollateralBalance } from './../../hooks';
import { LendingReserve } from "../../models/lending";
import { formatNumber } from "../../utils/utils";
import { Button, Card } from "antd";
import { useParams } from "react-router-dom";
import { cache, useAccount } from "../../contexts/accounts";
import { NumericInput } from "../../components/Input/numeric";
import { useConnection } from "../../contexts/connection";
import { useWallet } from "../../contexts/wallet";
import { deposit } from './../../actions/deposit';
import { Card } from "antd";
import './style.less';
import { PublicKey } from "@solana/web3.js";

View File

@ -1,30 +1,11 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from './../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button, Card } from "antd";
import { useParams } from "react-router-dom";
import { cache, useAccount } from "../../contexts/accounts";
import { NumericInput } from "../../components/Input/numeric";
import { useConnection } from "../../contexts/connection";
import { useWallet } from "../../contexts/wallet";
import { deposit } from './../../actions/deposit';
import React, { useState } from "react";
import { LendingReserve } from "../../models/lending";
import { Card } from "antd";
import { PublicKey } from "@solana/web3.js";
import './style.less';
export const ReserveStatus = (props: { className?: string, reserve: LendingReserve, address: PublicKey }) => {
const connection = useConnection();
const { wallet } = useWallet();
const { id } = useParams<{ id: string }>();
const [value, setValue] = useState('');
const reserve = props.reserve;
const address = props.address;
const name = useTokenName(reserve?.liquidityMint);
const { balance: tokenBalance, accounts: fromAccounts } = useUserBalance(reserve?.liquidityMint);
const [] = useState('');
const bodyStyle: React.CSSProperties = {
display: 'flex',

View File

@ -1,11 +1,10 @@
import React, { useMemo } from "react";
import { useCollateralBalance, useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from './../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber, formatPct, fromLamports } from "../../utils/utils";
import React from "react";
import { useCollateralBalance, useTokenName, useUserBalance } from './../../hooks';
import { LendingReserve } from "../../models/lending";
import { formatNumber, fromLamports } from "../../utils/utils";
import { Button, Card, Typography } from "antd";
import { Link, useParams } from "react-router-dom";
import { useAccount, useMint } from "../../contexts/accounts";
import { Link } from "react-router-dom";
import { useMint } from "../../contexts/accounts";
import { PublicKey } from "@solana/web3.js";
const { Text } = Typography;
@ -24,7 +23,6 @@ export const UserLendingCard = (props: {
const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint);
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
const totalLiquidity = fromLamports(props.reserve.totalLiquidity.toNumber(), liquidityMint);
// TODO: calculate
const borrowed = 0;

View File

@ -352,13 +352,17 @@ export const getMultipleAccounts = async (
.map(
(a) =>
a.array.map((acc) => {
if(!acc) {
return;
}
const { data, ...rest } = acc;
const obj = {
...rest,
data: Buffer.from(data[0], "base64"),
} as AccountInfo<Buffer>;
return obj;
}) as AccountInfo<Buffer>[]
}).filter(_ => _) as AccountInfo<Buffer>[]
)
.flat();
return { keys, array };

View File

@ -1,10 +1,9 @@
import React, { useCallback, useContext, useEffect, useState } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { useConnection } from "./connection";
import { LENDING_PROGRAM_ID } from "./../constants/ids";
import { LendingReserveLayout, LendingMarketLayout, LendingMarket, LendingMarketParser, isLendingReserve, isLendingMarket, LendingReserveParser, LendingReserve } from "./../models/lending";
import { cache, getMultipleAccounts, ParsedAccount } from "./accounts";
import { AccountInfo, PublicKey } from "@solana/web3.js";
import { isForInStatement } from "typescript";
import { LendingMarketParser, isLendingReserve, isLendingMarket, LendingReserveParser, LendingReserve } from "./../models/lending";
import { cache, getMultipleAccounts } from "./accounts";
import { PublicKey } from "@solana/web3.js";
export interface LendingContextState {
@ -64,7 +63,6 @@ export const useLending = () => {
await getMultipleAccounts(connection, toQuery, "single").then(
({ keys, array }) => {
return array.map((obj, index) => {
const pubKey = new PublicKey(keys[index]);
// TODO: add to cache
return obj;

View File

@ -1,16 +1,19 @@
import { PublicKey } from "@solana/web3.js";
import { useMemo } from "react";
import { useAccount, useMint } from "../contexts/accounts";
import { useMint } from "../contexts/accounts";
import { LendingReserve } from "../models/lending";
import { fromLamports } from "../utils/utils";
import { useUserAccounts } from "./useUserAccounts";
import { useUserBalance } from "./useUserBalance";
export function useCollateralBalance(reserve?: LendingReserve) {
const mint = useMint(reserve?.collateralMint);
const { balance: nativeBalance, accounts } = useUserBalance(reserve?.collateralMint, true);
const { balanceLamports, accounts } = useUserBalance(reserve?.collateralMint);
const balance = fromLamports((reserve?.totalLiquidity.toNumber() || 0) * (nativeBalance / (reserve?.collateralMintSupply.toNumber() || 1)), mint);
const collateralRatioLamports =
(reserve?.totalLiquidity.toNumber() || 0) *
(balanceLamports / (reserve?.collateralMintSupply.toNumber() || 1));
return { balance, accounts };
return {
balance: fromLamports(collateralRatioLamports, mint),
balanceLamports: collateralRatioLamports,
accounts
};
}

View File

@ -4,7 +4,7 @@ import { useMint } from "../contexts/accounts";
import { fromLamports } from "../utils/utils";
import { useUserAccounts } from "./useUserAccounts";
export function useUserBalance(mint?: PublicKey, inLamports = false) {
export function useUserBalance(mint?: PublicKey) {
const { userAccounts } = useUserAccounts();
const mintInfo = useMint(mint);
const accounts = useMemo(() => {
@ -13,11 +13,14 @@ export function useUserBalance(mint?: PublicKey, inLamports = false) {
.sort((a, b) => b.info.amount.sub(a.info.amount).toNumber());
}, [userAccounts]);
const balance = useMemo(() => {
const result = accounts
const balanceLamports = useMemo(() => {
return accounts
.reduce((res, item) => res += item.info.amount.toNumber(), 0);
return inLamports ? result : fromLamports(result , mintInfo);
},[accounts, mintInfo]);
return { balance, accounts };
return {
balance: fromLamports(balanceLamports, mintInfo),
balanceLamports,
accounts,
};
}

View File

@ -1,8 +1,6 @@
import {
AccountInfo,
Connection,
PublicKey,
sendAndConfirmRawTransaction,
SYSVAR_CLOCK_PUBKEY,
SYSVAR_RENT_PUBKEY,
TransactionInstruction,
@ -10,7 +8,6 @@ import {
import BN from "bn.js";
import * as BufferLayout from "buffer-layout";
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../../constants/ids";
import { sendTransaction } from "../../contexts/connection";
import * as Layout from "./../../utils/layout";
import { LendingInstruction } from './lending';

View File

@ -1,23 +1,14 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button, Card } from "antd";
import React, { } from "react";
import { useLendingReserve } from '../../hooks';
import { useParams } from "react-router-dom";
import { cache, useAccount } from "../../contexts/accounts";
import { NumericInput } from "../../components/Input/numeric";
import { useConnection } from "../../contexts/connection";
import { useWallet } from "../../contexts/wallet";
import { deposit } from '../../actions/deposit';
import './style.less';
import { BorrowInput } from '../../components/BorrowInput';
import { SideReserveOverview, SideReserveOverviewMode } from '../../components/SideReserveOverview';
export const BorrowReserveView = () => {
const connection = useConnection();
const { wallet } = useWallet();
const { id } = useParams<{ id: string }>();
const lendingReserve = useLendingReserve(id);
const reserve = lendingReserve?.info;

View File

@ -1,5 +1,5 @@
import React, { useMemo } from "react";
import { useCollateralBalance, useTokenName, useUserAccounts, useUserBalance } from '../../../hooks';
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";

View File

@ -1,15 +1,6 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button, Card } from "antd";
import React, { } from "react";
import { useLendingReserve } from '../../hooks';
import { useParams } from "react-router-dom";
import { cache, useAccount } from "../../contexts/accounts";
import { NumericInput } from "../../components/Input/numeric";
import { useConnection } from "../../contexts/connection";
import { useWallet } from "../../contexts/wallet";
import { deposit } from '../../actions/deposit';
import './style.less';
import { DepositInput } from '../../components/DepositInput';
@ -17,8 +8,6 @@ import { DepositInfoLine } from '../../components/DepositInfoLine';
import { SideReserveOverview, SideReserveOverviewMode } from '../../components/SideReserveOverview';
export const DepositReserveView = () => {
const connection = useConnection();
const { wallet } = useWallet();
const { id } = useParams<{ id: string }>();
const lendingReserve = useLendingReserve(id);
const reserve = lendingReserve?.info;

View File

@ -1,9 +1,5 @@
import React, { useMemo } from "react";
import { useLendingReserves, useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button } from "antd";
import React from "react";
import { useLendingReserves } from '../../hooks';
import { LendingReserveItem } from "./item";
import './itemStyle.less';

View File

@ -1,24 +1,12 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from './../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button, Card } from "antd";
import React, { } from "react";
import { useLendingReserve } from './../../hooks';
import { useParams } from "react-router-dom";
import { cache, useAccount } from "../../contexts/accounts";
import { NumericInput } from "../../components/Input/numeric";
import { useConnection } from "../../contexts/connection";
import { useWallet } from "../../contexts/wallet";
import { deposit } from './../../actions/deposit';
import './style.less';
import { DepositInput } from '../../components/DepositInput';
import { UserLendingCard } from './../../components/UserLendingCard';
import { ReserveStatus } from './../../components/ReserveStatus';
export const ReserveView = () => {
const connection = useConnection();
const { wallet } = useWallet();
const { id } = useParams<{ id: string }>();
const lendingReserve = useLendingReserve(id);
const reserve = lendingReserve?.info;