chore: cleanup layout

This commit is contained in:
bartosz-lipinski 2020-11-19 19:42:11 -06:00
parent 62af878032
commit 5cd9478317
18 changed files with 354 additions and 71 deletions

130
src/actions/borrow.tsx Normal file
View File

@ -0,0 +1,130 @@
import {
Account,
AccountInfo,
Connection,
PublicKey,
sendAndConfirmRawTransaction,
SYSVAR_CLOCK_PUBKEY,
TransactionInstruction,
} from "@solana/web3.js";
import BN from "bn.js";
import * as BufferLayout from "buffer-layout";
import { sendTransaction } from "../contexts/connection";
import { notify } from "../utils/notifications";
import * as Layout from "./../utils/layout";
import { depositInstruction, initReserveInstruction, LendingReserve } from "./../models/lending/reserve";
import { AccountLayout, MintInfo, Token } from "@solana/spl-token";
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../constants/ids";
import { createUninitializedAccount, ensureSplAccount, findOrCreateAccountByMint } from "./account";
import { cache, GenericAccountParser, MintParser, ParsedAccount } from "../contexts/accounts";
import { TokenAccount } from "../models";
import { isConstructorDeclaration } from "typescript";
import { LendingMarketParser } from "../models/lending";
import { sign } from "crypto";
import { fromLamports, toLamports } from "../utils/utils";
export const borrow = async (
from: TokenAccount,
amount: number,
reserve: LendingReserve,
reserveAddress: PublicKey,
connection: Connection,
wallet: any) => {
notify({
message: "Borrowing funds...",
description: "Please review transactions to approve.",
type: "warn",
});
const isInitalized = true; // TODO: finish reserve init
// user from account
const signers: Account[] = [];
const instructions: TransactionInstruction[] = [];
const cleanupInstructions: TransactionInstruction[] = [];
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
AccountLayout.span
);
const [authority] = await PublicKey.findProgramAddress(
[reserve.lendingMarket.toBuffer()], // which account should be authority
LENDING_PROGRAM_ID
);
const mint = (await cache.query(connection, reserve.liquidityMint, MintParser)) as ParsedAccount<MintInfo>;
const amountLamports = toLamports(amount, mint?.info);
const fromAccount = ensureSplAccount(
instructions,
cleanupInstructions,
from,
wallet.publicKey,
amountLamports + accountRentExempt,
signers
);
// create approval for transfer transactions
instructions.push(
Token.createApproveInstruction(
TOKEN_PROGRAM_ID,
fromAccount,
authority,
wallet.publicKey,
[],
amountLamports,
)
);
let toAccount: PublicKey;
if (isInitalized) {
// get destination account
toAccount = await findOrCreateAccountByMint(
wallet.publicKey,
wallet.publicKey,
instructions,
cleanupInstructions,
accountRentExempt,
reserve.collateralMint,
signers
);
} else {
toAccount = createUninitializedAccount(
instructions,
wallet.publicKey,
accountRentExempt,
signers,
);
}
// deposit
instructions.push(
depositInstruction(
amountLamports,
fromAccount,
toAccount,
authority,
reserveAddress,
reserve.liquiditySupply,
reserve.collateralMint,
)
);
try {
let tx = await sendTransaction(
connection,
wallet,
instructions.concat(cleanupInstructions),
signers,
true
);
notify({
message: "Funds borrowed.",
type: "success",
description: `Transaction - ${tx}`,
});
} catch {
// TODO:
}
}

3
src/actions/index.ts Normal file
View File

@ -0,0 +1,3 @@
export { borrow } from './borrow';
export { deposit } from './deposit';
export * from './account';

View File

@ -0,0 +1,74 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models/lending";
import { TokenIcon } from "../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 "../Input/numeric";
import { useConnection } from "../../contexts/connection";
import { useWallet } from "../../contexts/wallet";
import { borrow } from '../../actions';
import { PublicKey } from "@solana/web3.js";
import './style.less';
export const BorrowInput = (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 collateralBalance = useUserBalance(reserve?.collateralMint);
const onBorrow = useCallback(() => {
borrow(
fromAccounts[0],
parseFloat(value),
reserve,
address,
connection,
wallet);
}, [value, reserve, fromAccounts, address]);
const bodyStyle: React.CSSProperties = {
display: 'flex',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
height: '100%',
};
return <Card className={props.className} bodyStyle={bodyStyle}>
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-around' }}>
<div className="borrow-input-title">
How much would you like to borrow?
</div>
<div className="token-input">
<TokenIcon mintAddress={reserve?.liquidityMint} />
<NumericInput value={value}
onChange={(val: any) => {
setValue(val);
}}
autoFocus={true}
style={{
fontSize: 20,
boxShadow: "none",
borderColor: "transparent",
outline: "transpaernt",
}}
placeholder="0.00"
/>
<div>{name}</div>
</div>
<Button type="primary" onClick={onBorrow} disabled={fromAccounts.length === 0}>Borrow</Button>
</div>
</Card >;
}

View File

@ -0,0 +1,3 @@
.borrow-input-title {
font-size: 1.05rem;
}

View File

@ -1,3 +0,0 @@
.deposit-add-title {
font-size: 1.05rem;
}

View File

@ -1,19 +1,19 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from './../../hooks';
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { TokenIcon } from "../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 { NumericInput } from "../Input/numeric";
import { useConnection } from "../../contexts/connection";
import { useWallet } from "../../contexts/wallet";
import { deposit } from './../../actions/deposit';
import { deposit } from '../../actions/deposit';
import { PublicKey } from "@solana/web3.js";
import './style.less';
export const DepositAdd = (props: { className?: string, reserve: LendingReserve, address: PublicKey }) => {
export const DepositInput = (props: { className?: string, reserve: LendingReserve, address: PublicKey }) => {
const connection = useConnection();
const { wallet } = useWallet();
const { id } = useParams<{ id: string }>();
@ -66,7 +66,7 @@ export const DepositAdd = (props: { className?: string, reserve: LendingReserve,
return <Card className={props.className} bodyStyle={bodyStyle}>
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-around' }}>
<div className="deposit-add-title">
<div className="deposit-input-title">
How much would you like to deposit?
</div>
<div className="token-input">

View File

@ -0,0 +1,3 @@
.deposit-input-title {
font-size: 1.05rem;
}

View File

@ -101,7 +101,7 @@ export const UserLendingCard = (props: {
<Button>Deposit</Button>
</Link>
<Link to={`/borrow/${address}`}>
<Button disabled={true}>Borrow</Button>
<Button>Borrow</Button>
</Link>
<Link to={`/withdraw/${address}`}>
<Button disabled={true}>Withdraw</Button>

View File

@ -50,8 +50,6 @@ export const useLending = () => {
.map(processAccount)
.filter(item => item !== undefined);
console.log(accounts);
const toQuery = [
...accounts.filter(acc => (acc?.info as LendingReserve).lendingMarket !== undefined)
.map(acc => [

View File

@ -10,10 +10,11 @@ import { AppLayout } from "./components/Layout";
import {
HomeView,
DepositView,
DepositAddView,
DepositReserveView,
BorrowView,
ReserveView,
DashboardView,
BorrowReserveView,
} from './views';
export function Routes() {
@ -31,8 +32,9 @@ export function Routes() {
<Route exact path="/dashboard" children={<DashboardView />} />
<Route path="/reserve/:id" children={<ReserveView />} />
<Route exact path="/deposit" component={() => <DepositView />} />
<Route path="/deposit/:id" children={<DepositAddView />} />
<Route path="/deposit/:id" children={<DepositReserveView />} />
<Route exact path="/borrow" children={<BorrowView />} />
<Route path="/borrow/:id" children={<BorrowReserveView />} />
</Switch>
</AppLayout>
</LendingProvider>

View File

@ -0,0 +1,42 @@
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 './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;
if (!reserve || !lendingReserve) {
return null;
}
return <div className="borrow-reserve">
<div className="borrow-reserve-container">
<BorrowInput
className="borrow-reserve-item borrow-reserve-item-left"
reserve={reserve}
address={lendingReserve.pubkey} />
<SideReserveOverview
className="borrow-reserve-item borrow-reserve-item-right"
reserve={reserve}
address={lendingReserve.pubkey}
mode={SideReserveOverviewMode.Borrow} />
</div>
</div>;
}

View File

@ -1,30 +1,30 @@
.deposit-add {
.borrow-reserve {
display: flex;
flex-direction: column;
flex: 1;
}
.deposit-add-item {
.borrow-reserve-item {
margin: 4px;
}
.deposit-add-container {
.borrow-reserve-container {
display: flex;
flex-wrap: wrap;
flex: 1;
}
.deposit-add-item-left {
.borrow-reserve-item-left {
flex: 60%;
}
.deposit-add-item-right {
.borrow-reserve-item-right {
flex: 30%;
}
/* Responsive layout - makes a one column layout instead of a two-column layout */
@media (max-width: 600px) {
.deposit-add-item-right, .deposit-add-item-left {
.borrow-reserve-item-right, .borrow-reserve-item-left {
flex: 100%;
}
}

View File

@ -1,47 +0,0 @@
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 './style.less';
import { DepositAdd } from './../../../components/DepositAdd';
import { DepositInfoLine } from './../../../components/DepositInfoLine';
import { SideReserveOverview, SideReserveOverviewMode } from './../../../components/SideReserveOverview';
export const DepositAddView = () => {
const connection = useConnection();
const { wallet } = useWallet();
const { id } = useParams<{ id: string }>();
const lendingReserve = useLendingReserve(id);
const reserve = lendingReserve?.info;
if (!reserve || !lendingReserve) {
return null;
}
return <div className="deposit-add">
<DepositInfoLine
className="deposit-add-item"
reserve={reserve}
address={lendingReserve.pubkey} />
<div className="deposit-add-container">
<DepositAdd
className="deposit-add-item deposit-add-item-left"
reserve={reserve}
address={lendingReserve.pubkey} />
<SideReserveOverview
className="deposit-add-item deposit-add-item-right"
reserve={reserve}
address={lendingReserve.pubkey}
mode={SideReserveOverviewMode.Deposit} />
</div>
</div>;
}

View File

@ -1,2 +1 @@
export * from './view';
export * from './add';
export * from './view';

View File

@ -0,0 +1,47 @@
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 './style.less';
import { DepositInput } from '../../components/DepositInput';
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;
if (!reserve || !lendingReserve) {
return null;
}
return <div className="deposit-reserve">
<DepositInfoLine
className="deposit-reserve-item"
reserve={reserve}
address={lendingReserve.pubkey} />
<div className="deposit-reserve-container">
<DepositInput
className="deposit-reserve-item deposit-reserve-item-left"
reserve={reserve}
address={lendingReserve.pubkey} />
<SideReserveOverview
className="deposit-reserve-item deposit-reserve-item-right"
reserve={reserve}
address={lendingReserve.pubkey}
mode={SideReserveOverviewMode.Deposit} />
</div>
</div>;
}

View File

@ -0,0 +1,30 @@
.deposit-reserve {
display: flex;
flex-direction: column;
flex: 1;
}
.deposit-reserve-item {
margin: 4px;
}
.deposit-reserve-container {
display: flex;
flex-wrap: wrap;
flex: 1;
}
.deposit-reserve-item-left {
flex: 60%;
}
.deposit-reserve-item-right {
flex: 30%;
}
/* Responsive layout - makes a one column layout instead of a two-column layout */
@media (max-width: 600px) {
.deposit-reserve-item-right, .deposit-reserve-item-left {
flex: 100%;
}
}

View File

@ -1,5 +1,7 @@
export { HomeView } from './home';
export { BorrowView } from './borrow';
export { BorrowReserveView } from './borrowReserve';
export { DashboardView } from './dashboard';
export { DepositView, DepositAddView } from './deposit';
export { DepositView } from './deposit';
export { DepositReserveView } from './depositReserve';
export { ReserveView } from './reserve';

View File

@ -12,7 +12,7 @@ import { useWallet } from "../../contexts/wallet";
import { deposit } from './../../actions/deposit';
import './style.less';
import { DepositAdd } from './../../components/DepositAdd';
import { DepositInput } from '../../components/DepositInput';
import { UserLendingCard } from './../../components/UserLendingCard';
import { ReserveStatus } from './../../components/ReserveStatus';