mirror of https://github.com/certusone/oyster.git
chore: prettier
This commit is contained in:
parent
547ab00d7b
commit
5ea0434a68
|
@ -2,11 +2,8 @@ import React from "react";
|
||||||
import "./App.less";
|
import "./App.less";
|
||||||
import { Routes } from "./routes";
|
import { Routes } from "./routes";
|
||||||
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return <Routes />;
|
||||||
<Routes />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
import { AccountLayout, Token } from "@solana/spl-token";
|
import { AccountLayout, Token } from "@solana/spl-token";
|
||||||
import { Account, PublicKey, SystemProgram, TransactionInstruction } from "@solana/web3.js";
|
import {
|
||||||
|
Account,
|
||||||
|
PublicKey,
|
||||||
|
SystemProgram,
|
||||||
|
TransactionInstruction,
|
||||||
|
} from "@solana/web3.js";
|
||||||
import { TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT } from "../constants/ids";
|
import { TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT } from "../constants/ids";
|
||||||
import { TokenAccount } from "../models";
|
import { TokenAccount } from "../models";
|
||||||
import { cache, TokenAccountParser } from './../contexts/accounts';
|
import { cache, TokenAccountParser } from "./../contexts/accounts";
|
||||||
|
|
||||||
export function ensureSplAccount(
|
export function ensureSplAccount(
|
||||||
instructions: TransactionInstruction[],
|
instructions: TransactionInstruction[],
|
||||||
|
@ -20,7 +25,8 @@ export function ensureSplAccount(
|
||||||
instructions,
|
instructions,
|
||||||
payer,
|
payer,
|
||||||
amount,
|
amount,
|
||||||
signers);
|
signers
|
||||||
|
);
|
||||||
|
|
||||||
instructions.push(
|
instructions.push(
|
||||||
Token.createInitAccountInstruction(
|
Token.createInitAccountInstruction(
|
||||||
|
@ -50,7 +56,8 @@ export function createTempMemoryAccount(
|
||||||
instructions: TransactionInstruction[],
|
instructions: TransactionInstruction[],
|
||||||
payer: PublicKey,
|
payer: PublicKey,
|
||||||
signers: Account[],
|
signers: Account[],
|
||||||
space = DEFAULT_TEMP_MEM_SPACE) {
|
space = DEFAULT_TEMP_MEM_SPACE
|
||||||
|
) {
|
||||||
const account = new Account();
|
const account = new Account();
|
||||||
instructions.push(
|
instructions.push(
|
||||||
SystemProgram.createAccount({
|
SystemProgram.createAccount({
|
||||||
|
@ -68,12 +75,12 @@ export function createTempMemoryAccount(
|
||||||
return account.publicKey;
|
return account.publicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function createUninitializedAccount(
|
export function createUninitializedAccount(
|
||||||
instructions: TransactionInstruction[],
|
instructions: TransactionInstruction[],
|
||||||
payer: PublicKey,
|
payer: PublicKey,
|
||||||
amount: number,
|
amount: number,
|
||||||
signers: Account[]) {
|
signers: Account[]
|
||||||
|
) {
|
||||||
const account = new Account();
|
const account = new Account();
|
||||||
instructions.push(
|
instructions.push(
|
||||||
SystemProgram.createAccount({
|
SystemProgram.createAccount({
|
||||||
|
@ -96,21 +103,17 @@ export function createTokenAccount(
|
||||||
accountRentExempt: number,
|
accountRentExempt: number,
|
||||||
mint: PublicKey,
|
mint: PublicKey,
|
||||||
owner: PublicKey,
|
owner: PublicKey,
|
||||||
signers: Account[],
|
signers: Account[]
|
||||||
) {
|
) {
|
||||||
const account = createUninitializedAccount(
|
const account = createUninitializedAccount(
|
||||||
instructions,
|
instructions,
|
||||||
payer,
|
payer,
|
||||||
accountRentExempt,
|
accountRentExempt,
|
||||||
signers);
|
signers
|
||||||
|
);
|
||||||
|
|
||||||
instructions.push(
|
instructions.push(
|
||||||
Token.createInitAccountInstruction(
|
Token.createInitAccountInstruction(TOKEN_PROGRAM_ID, mint, account, owner)
|
||||||
TOKEN_PROGRAM_ID,
|
|
||||||
mint,
|
|
||||||
account,
|
|
||||||
owner
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return account;
|
return account;
|
||||||
|
@ -128,8 +131,9 @@ export function findOrCreateAccountByMint(
|
||||||
excluded?: Set<string>
|
excluded?: Set<string>
|
||||||
): PublicKey {
|
): PublicKey {
|
||||||
const accountToFind = mint.toBase58();
|
const accountToFind = mint.toBase58();
|
||||||
const account = cache.byParser(TokenAccountParser)
|
const account = cache
|
||||||
.map(id => cache.get(id))
|
.byParser(TokenAccountParser)
|
||||||
|
.map((id) => cache.get(id))
|
||||||
.find(
|
.find(
|
||||||
(acc) =>
|
(acc) =>
|
||||||
acc !== undefined &&
|
acc !== undefined &&
|
||||||
|
@ -150,7 +154,7 @@ export function findOrCreateAccountByMint(
|
||||||
accountRentExempt,
|
accountRentExempt,
|
||||||
mint,
|
mint,
|
||||||
owner,
|
owner,
|
||||||
signers,
|
signers
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isWrappedSol) {
|
if (isWrappedSol) {
|
||||||
|
|
|
@ -9,11 +9,20 @@ import { notify } from "../utils/notifications";
|
||||||
import { LendingReserve } from "./../models/lending/reserve";
|
import { LendingReserve } from "./../models/lending/reserve";
|
||||||
import { AccountLayout, MintInfo, MintLayout, Token } from "@solana/spl-token";
|
import { AccountLayout, MintInfo, MintLayout, Token } from "@solana/spl-token";
|
||||||
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../constants/ids";
|
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../constants/ids";
|
||||||
import { createTempMemoryAccount, createUninitializedAccount, ensureSplAccount, findOrCreateAccountByMint } from "./account";
|
import {
|
||||||
|
createTempMemoryAccount,
|
||||||
|
createUninitializedAccount,
|
||||||
|
ensureSplAccount,
|
||||||
|
findOrCreateAccountByMint,
|
||||||
|
} from "./account";
|
||||||
import { cache, MintParser, ParsedAccount } from "../contexts/accounts";
|
import { cache, MintParser, ParsedAccount } from "../contexts/accounts";
|
||||||
import { TokenAccount, LendingObligationLayout, borrowInstruction, LendingMarket } from "../models";
|
import {
|
||||||
|
TokenAccount,
|
||||||
|
LendingObligationLayout,
|
||||||
|
borrowInstruction,
|
||||||
|
LendingMarket,
|
||||||
|
} from "../models";
|
||||||
import { toLamports } from "../utils/utils";
|
import { toLamports } from "../utils/utils";
|
||||||
import { DexMarketParser } from "../models/dex";
|
|
||||||
|
|
||||||
export const borrow = async (
|
export const borrow = async (
|
||||||
from: TokenAccount,
|
from: TokenAccount,
|
||||||
|
@ -26,8 +35,8 @@ export const borrow = async (
|
||||||
depositReserveAddress: PublicKey,
|
depositReserveAddress: PublicKey,
|
||||||
|
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
wallet: any) => {
|
wallet: any
|
||||||
|
) => {
|
||||||
notify({
|
notify({
|
||||||
message: "Borrowing funds...",
|
message: "Borrowing funds...",
|
||||||
description: "Please review transactions to approve.",
|
description: "Please review transactions to approve.",
|
||||||
|
@ -48,23 +57,21 @@ export const borrow = async (
|
||||||
await connection.getMinimumBalanceForRentExemption(
|
await connection.getMinimumBalanceForRentExemption(
|
||||||
LendingObligationLayout.span
|
LendingObligationLayout.span
|
||||||
),
|
),
|
||||||
signers,
|
signers
|
||||||
);
|
);
|
||||||
|
|
||||||
const obligationMint = createUninitializedAccount(
|
const obligationMint = createUninitializedAccount(
|
||||||
instructions,
|
instructions,
|
||||||
wallet.publicKey,
|
wallet.publicKey,
|
||||||
await connection.getMinimumBalanceForRentExemption(
|
await connection.getMinimumBalanceForRentExemption(MintLayout.span),
|
||||||
MintLayout.span
|
signers
|
||||||
),
|
|
||||||
signers,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const obligationTokenOutput = createUninitializedAccount(
|
const obligationTokenOutput = createUninitializedAccount(
|
||||||
instructions,
|
instructions,
|
||||||
wallet.publicKey,
|
wallet.publicKey,
|
||||||
accountRentExempt,
|
accountRentExempt,
|
||||||
signers,
|
signers
|
||||||
);
|
);
|
||||||
|
|
||||||
let toAccount = await findOrCreateAccountByMint(
|
let toAccount = await findOrCreateAccountByMint(
|
||||||
|
@ -78,7 +85,9 @@ export const borrow = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
// create all accounts in one transaction
|
// create all accounts in one transaction
|
||||||
let tx = await sendTransaction(connection, wallet, instructions, [...signers]);
|
let tx = await sendTransaction(connection, wallet, instructions, [
|
||||||
|
...signers,
|
||||||
|
]);
|
||||||
|
|
||||||
notify({
|
notify({
|
||||||
message: "Obligation accounts created",
|
message: "Obligation accounts created",
|
||||||
|
@ -101,7 +110,11 @@ export const borrow = async (
|
||||||
LENDING_PROGRAM_ID
|
LENDING_PROGRAM_ID
|
||||||
);
|
);
|
||||||
|
|
||||||
const mint = (await cache.query(connection, depositReserve.collateralMint, MintParser)) as ParsedAccount<MintInfo>;
|
const mint = (await cache.query(
|
||||||
|
connection,
|
||||||
|
depositReserve.collateralMint,
|
||||||
|
MintParser
|
||||||
|
)) as ParsedAccount<MintInfo>;
|
||||||
const amountLamports = toLamports(amount, mint?.info);
|
const amountLamports = toLamports(amount, mint?.info);
|
||||||
|
|
||||||
const fromAccount = ensureSplAccount(
|
const fromAccount = ensureSplAccount(
|
||||||
|
@ -121,27 +134,33 @@ export const borrow = async (
|
||||||
authority,
|
authority,
|
||||||
wallet.publicKey,
|
wallet.publicKey,
|
||||||
[],
|
[],
|
||||||
amountLamports,
|
amountLamports
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const market = cache.get(depositReserve.lendingMarket) as ParsedAccount<LendingMarket>;
|
const market = cache.get(depositReserve.lendingMarket) as ParsedAccount<
|
||||||
|
LendingMarket
|
||||||
|
>;
|
||||||
|
|
||||||
const dexMarketAddress = borrowReserve.dexMarketOption ? borrowReserve.dexMarket : depositReserve.dexMarket;
|
const dexMarketAddress = borrowReserve.dexMarketOption
|
||||||
|
? borrowReserve.dexMarket
|
||||||
|
: depositReserve.dexMarket;
|
||||||
const dexMarket = cache.get(dexMarketAddress);
|
const dexMarket = cache.get(dexMarketAddress);
|
||||||
|
|
||||||
if(!dexMarket) {
|
if (!dexMarket) {
|
||||||
throw new Error(`Dex market doesn't exsists.`)
|
throw new Error(`Dex market doesn't exsists.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dexOrderBookSide = market.info.quoteMint.equals(depositReserve.liquidityMint) ?
|
const dexOrderBookSide = market.info.quoteMint.equals(
|
||||||
dexMarket?.info.bids :
|
depositReserve.liquidityMint
|
||||||
dexMarket?.info.asks
|
)
|
||||||
|
? dexMarket?.info.bids
|
||||||
|
: dexMarket?.info.asks;
|
||||||
|
|
||||||
const memory = createTempMemoryAccount(
|
const memory = createTempMemoryAccount(
|
||||||
instructions,
|
instructions,
|
||||||
wallet.publicKey,
|
wallet.publicKey,
|
||||||
signers,
|
signers
|
||||||
);
|
);
|
||||||
|
|
||||||
// deposit
|
// deposit
|
||||||
|
@ -165,7 +184,7 @@ export const borrow = async (
|
||||||
dexMarketAddress,
|
dexMarketAddress,
|
||||||
dexOrderBookSide,
|
dexOrderBookSide,
|
||||||
|
|
||||||
memory,
|
memory
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
|
@ -185,4 +204,4 @@ export const borrow = async (
|
||||||
} catch {
|
} catch {
|
||||||
// TODO:
|
// TODO:
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -6,10 +6,18 @@ import {
|
||||||
} from "@solana/web3.js";
|
} from "@solana/web3.js";
|
||||||
import { sendTransaction } from "../contexts/connection";
|
import { sendTransaction } from "../contexts/connection";
|
||||||
import { notify } from "../utils/notifications";
|
import { notify } from "../utils/notifications";
|
||||||
import { depositInstruction, initReserveInstruction, LendingReserve } from "./../models/lending/reserve";
|
import {
|
||||||
|
depositInstruction,
|
||||||
|
initReserveInstruction,
|
||||||
|
LendingReserve,
|
||||||
|
} from "./../models/lending/reserve";
|
||||||
import { AccountLayout, MintInfo, Token } from "@solana/spl-token";
|
import { AccountLayout, MintInfo, Token } from "@solana/spl-token";
|
||||||
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../constants/ids";
|
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../constants/ids";
|
||||||
import { createUninitializedAccount, ensureSplAccount, findOrCreateAccountByMint } from "./account";
|
import {
|
||||||
|
createUninitializedAccount,
|
||||||
|
ensureSplAccount,
|
||||||
|
findOrCreateAccountByMint,
|
||||||
|
} from "./account";
|
||||||
import { cache, MintParser, ParsedAccount } from "../contexts/accounts";
|
import { cache, MintParser, ParsedAccount } from "../contexts/accounts";
|
||||||
import { TokenAccount } from "../models";
|
import { TokenAccount } from "../models";
|
||||||
import { toLamports } from "../utils/utils";
|
import { toLamports } from "../utils/utils";
|
||||||
|
@ -20,8 +28,8 @@ export const deposit = async (
|
||||||
reserve: LendingReserve,
|
reserve: LendingReserve,
|
||||||
reserveAddress: PublicKey,
|
reserveAddress: PublicKey,
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
wallet: any) => {
|
wallet: any
|
||||||
|
) => {
|
||||||
// TODO: customize ?
|
// TODO: customize ?
|
||||||
const MAX_UTILIZATION_RATE = 80;
|
const MAX_UTILIZATION_RATE = 80;
|
||||||
|
|
||||||
|
@ -47,7 +55,11 @@ export const deposit = async (
|
||||||
LENDING_PROGRAM_ID
|
LENDING_PROGRAM_ID
|
||||||
);
|
);
|
||||||
|
|
||||||
const mint = (await cache.query(connection, reserve.liquidityMint, MintParser)) as ParsedAccount<MintInfo>;
|
const mint = (await cache.query(
|
||||||
|
connection,
|
||||||
|
reserve.liquidityMint,
|
||||||
|
MintParser
|
||||||
|
)) as ParsedAccount<MintInfo>;
|
||||||
const amountLamports = toLamports(amount, mint?.info);
|
const amountLamports = toLamports(amount, mint?.info);
|
||||||
|
|
||||||
const fromAccount = ensureSplAccount(
|
const fromAccount = ensureSplAccount(
|
||||||
|
@ -67,7 +79,7 @@ export const deposit = async (
|
||||||
authority,
|
authority,
|
||||||
wallet.publicKey,
|
wallet.publicKey,
|
||||||
[],
|
[],
|
||||||
amountLamports,
|
amountLamports
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -88,7 +100,7 @@ export const deposit = async (
|
||||||
instructions,
|
instructions,
|
||||||
wallet.publicKey,
|
wallet.publicKey,
|
||||||
accountRentExempt,
|
accountRentExempt,
|
||||||
signers,
|
signers
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,12 +114,13 @@ export const deposit = async (
|
||||||
authority,
|
authority,
|
||||||
reserveAddress,
|
reserveAddress,
|
||||||
reserve.liquiditySupply,
|
reserve.liquiditySupply,
|
||||||
reserve.collateralMint,
|
reserve.collateralMint
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// TODO: finish reserve init
|
// TODO: finish reserve init
|
||||||
instructions.push(initReserveInstruction(
|
instructions.push(
|
||||||
|
initReserveInstruction(
|
||||||
amountLamports,
|
amountLamports,
|
||||||
MAX_UTILIZATION_RATE,
|
MAX_UTILIZATION_RATE,
|
||||||
fromAccount,
|
fromAccount,
|
||||||
|
@ -119,8 +132,9 @@ export const deposit = async (
|
||||||
reserve.collateralSupply,
|
reserve.collateralSupply,
|
||||||
reserve.lendingMarket,
|
reserve.lendingMarket,
|
||||||
authority,
|
authority,
|
||||||
reserve.dexMarket,
|
reserve.dexMarket
|
||||||
));
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -140,4 +154,4 @@ export const deposit = async (
|
||||||
} catch {
|
} catch {
|
||||||
// TODO:
|
// TODO:
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export { borrow } from './borrow';
|
export { borrow } from "./borrow";
|
||||||
export { deposit } from './deposit';
|
export { deposit } from "./deposit";
|
||||||
export { withdraw } from './withdraw';
|
export { withdraw } from "./withdraw";
|
||||||
export * from './account';
|
export * from "./account";
|
||||||
|
|
|
@ -6,7 +6,10 @@ import {
|
||||||
} from "@solana/web3.js";
|
} from "@solana/web3.js";
|
||||||
import { sendTransaction } from "../contexts/connection";
|
import { sendTransaction } from "../contexts/connection";
|
||||||
import { notify } from "../utils/notifications";
|
import { notify } from "../utils/notifications";
|
||||||
import { LendingReserve, withdrawInstruction } from "./../models/lending/reserve";
|
import {
|
||||||
|
LendingReserve,
|
||||||
|
withdrawInstruction,
|
||||||
|
} from "./../models/lending/reserve";
|
||||||
import { AccountLayout, Token } from "@solana/spl-token";
|
import { AccountLayout, Token } from "@solana/spl-token";
|
||||||
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../constants/ids";
|
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../constants/ids";
|
||||||
import { findOrCreateAccountByMint } from "./account";
|
import { findOrCreateAccountByMint } from "./account";
|
||||||
|
@ -18,8 +21,8 @@ export const withdraw = async (
|
||||||
reserve: LendingReserve,
|
reserve: LendingReserve,
|
||||||
reserveAddress: PublicKey,
|
reserveAddress: PublicKey,
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
wallet: any) => {
|
wallet: any
|
||||||
|
) => {
|
||||||
notify({
|
notify({
|
||||||
message: "Withdrawing funds...",
|
message: "Withdrawing funds...",
|
||||||
description: "Please review transactions to approve.",
|
description: "Please review transactions to approve.",
|
||||||
|
@ -50,7 +53,7 @@ export const withdraw = async (
|
||||||
authority,
|
authority,
|
||||||
wallet.publicKey,
|
wallet.publicKey,
|
||||||
[],
|
[],
|
||||||
amountLamports,
|
amountLamports
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -73,7 +76,7 @@ export const withdraw = async (
|
||||||
reserveAddress,
|
reserveAddress,
|
||||||
reserve.collateralMint,
|
reserve.collateralMint,
|
||||||
reserve.liquiditySupply,
|
reserve.liquiditySupply,
|
||||||
authority,
|
authority
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -94,4 +97,4 @@ export const withdraw = async (
|
||||||
} catch {
|
} catch {
|
||||||
// TODO:
|
// TODO:
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useCallback, useMemo, useState } from "react";
|
import React, { useCallback, useMemo, useState } from "react";
|
||||||
import { useLendingReserves, useTokenName, useUserBalance } from '../../hooks';
|
import { useLendingReserves, useTokenName, useUserBalance } from "../../hooks";
|
||||||
import { LendingReserve, LendingReserveParser } from "../../models";
|
import { LendingReserve, LendingReserveParser } from "../../models";
|
||||||
import { TokenIcon } from "../TokenIcon";
|
import { TokenIcon } from "../TokenIcon";
|
||||||
import { getTokenName } from "../../utils/utils";
|
import { getTokenName } from "../../utils/utils";
|
||||||
|
@ -8,9 +8,9 @@ import { cache, ParsedAccount } from "../../contexts/accounts";
|
||||||
import { NumericInput } from "../Input/numeric";
|
import { NumericInput } from "../Input/numeric";
|
||||||
import { useConnection, useConnectionConfig } from "../../contexts/connection";
|
import { useConnection, useConnectionConfig } from "../../contexts/connection";
|
||||||
import { useWallet } from "../../contexts/wallet";
|
import { useWallet } from "../../contexts/wallet";
|
||||||
import { borrow } from '../../actions';
|
import { borrow } from "../../actions";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import './style.less';
|
import "./style.less";
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@ const CollateralSelector = (props: {
|
||||||
const { reserveAccounts } = useLendingReserves();
|
const { reserveAccounts } = useLendingReserves();
|
||||||
const { tokenMap } = useConnectionConfig();
|
const { tokenMap } = useConnectionConfig();
|
||||||
|
|
||||||
return <Select
|
return (
|
||||||
|
<Select
|
||||||
size="large"
|
size="large"
|
||||||
showSearch
|
showSearch
|
||||||
style={{ minWidth: 120 }}
|
style={{ minWidth: 120 }}
|
||||||
|
@ -38,44 +39,54 @@ const CollateralSelector = (props: {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{reserveAccounts
|
{reserveAccounts
|
||||||
.filter(reserve => reserve.info !== props.reserve)
|
.filter((reserve) => reserve.info !== props.reserve)
|
||||||
.map(reserve => {
|
.map((reserve) => {
|
||||||
const mint = reserve.info.liquidityMint.toBase58();
|
const mint = reserve.info.liquidityMint.toBase58();
|
||||||
const address = reserve.pubkey.toBase58();
|
const address = reserve.pubkey.toBase58();
|
||||||
const name = getTokenName(tokenMap, mint);
|
const name = getTokenName(tokenMap, mint);
|
||||||
return <Option key={address} value={address} name={name} title={address}>
|
return (
|
||||||
<div key={address} style={{ display: "flex", alignItems: "center" }}>
|
<Option key={address} value={address} name={name} title={address}>
|
||||||
|
<div
|
||||||
|
key={address}
|
||||||
|
style={{ display: "flex", alignItems: "center" }}
|
||||||
|
>
|
||||||
<TokenIcon mintAddress={mint} />
|
<TokenIcon mintAddress={mint} />
|
||||||
{name}
|
{name}
|
||||||
</div>
|
</div>
|
||||||
</Option>
|
</Option>
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
</Select>;
|
</Select>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const BorrowInput = (props: { className?: string, reserve: LendingReserve, address: PublicKey }) => {
|
export const BorrowInput = (props: {
|
||||||
|
className?: string;
|
||||||
|
reserve: LendingReserve;
|
||||||
|
address: PublicKey;
|
||||||
|
}) => {
|
||||||
const connection = useConnection();
|
const connection = useConnection();
|
||||||
const { wallet } = useWallet();
|
const { wallet } = useWallet();
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState("");
|
||||||
|
|
||||||
const borrowReserve = props.reserve;
|
const borrowReserve = props.reserve;
|
||||||
const borrowReserveAddress = props.address;
|
const borrowReserveAddress = props.address;
|
||||||
|
|
||||||
const [collateralReserveMint, setCollateralReserveMint] = useState<string>();
|
const [collateralReserveMint, setCollateralReserveMint] = useState<string>();
|
||||||
|
|
||||||
|
|
||||||
const collateralReserve = useMemo(() => {
|
const collateralReserve = useMemo(() => {
|
||||||
const id: string = cache.byParser(LendingReserveParser)
|
const id: string =
|
||||||
.find(acc => acc === collateralReserveMint) || '';
|
cache
|
||||||
|
.byParser(LendingReserveParser)
|
||||||
|
.find((acc) => acc === collateralReserveMint) || "";
|
||||||
|
|
||||||
return cache.get(id) as ParsedAccount<LendingReserve>;
|
return cache.get(id) as ParsedAccount<LendingReserve>;
|
||||||
}, [collateralReserveMint])
|
}, [collateralReserveMint]);
|
||||||
|
|
||||||
|
|
||||||
const name = useTokenName(borrowReserve?.liquidityMint);
|
const name = useTokenName(borrowReserve?.liquidityMint);
|
||||||
const {
|
const { accounts: fromAccounts } = useUserBalance(
|
||||||
accounts: fromAccounts
|
collateralReserve?.info.collateralMint
|
||||||
} = useUserBalance(collateralReserve?.info.collateralMint);
|
);
|
||||||
// const collateralBalance = useUserBalance(reserve?.collateralMint);
|
// const collateralBalance = useUserBalance(reserve?.collateralMint);
|
||||||
|
|
||||||
const onBorrow = useCallback(() => {
|
const onBorrow = useCallback(() => {
|
||||||
|
@ -91,26 +102,42 @@ export const BorrowInput = (props: { className?: string, reserve: LendingReserve
|
||||||
collateralReserve.info,
|
collateralReserve.info,
|
||||||
collateralReserve.pubkey,
|
collateralReserve.pubkey,
|
||||||
connection,
|
connection,
|
||||||
wallet);
|
wallet
|
||||||
}, [value, borrowReserve, fromAccounts, borrowReserveAddress]);
|
);
|
||||||
|
}, [
|
||||||
|
connection,
|
||||||
|
wallet,
|
||||||
|
value,
|
||||||
|
collateralReserve,
|
||||||
|
borrowReserve,
|
||||||
|
fromAccounts,
|
||||||
|
borrowReserveAddress,
|
||||||
|
]);
|
||||||
|
|
||||||
const bodyStyle: React.CSSProperties = {
|
const bodyStyle: React.CSSProperties = {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
height: '100%',
|
height: "100%",
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Card className={props.className} bodyStyle={bodyStyle}>
|
return (
|
||||||
|
<Card className={props.className} bodyStyle={bodyStyle}>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-around' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="borrow-input-title">
|
<div className="borrow-input-title">
|
||||||
How much would you like to borrow?
|
How much would you like to borrow?
|
||||||
</div>
|
</div>
|
||||||
<div className="token-input">
|
<div className="token-input">
|
||||||
<TokenIcon mintAddress={borrowReserve?.liquidityMint} />
|
<TokenIcon mintAddress={borrowReserve?.liquidityMint} />
|
||||||
<NumericInput value={value}
|
<NumericInput
|
||||||
|
value={value}
|
||||||
onChange={(val: any) => {
|
onChange={(val: any) => {
|
||||||
setValue(val);
|
setValue(val);
|
||||||
}}
|
}}
|
||||||
|
@ -125,16 +152,21 @@ export const BorrowInput = (props: { className?: string, reserve: LendingReserve
|
||||||
/>
|
/>
|
||||||
<div>{name}</div>
|
<div>{name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="borrow-input-title">
|
<div className="borrow-input-title">Select collateral account?</div>
|
||||||
Select collateral account?
|
|
||||||
</div>
|
|
||||||
<CollateralSelector
|
<CollateralSelector
|
||||||
reserve={borrowReserve}
|
reserve={borrowReserve}
|
||||||
mint={collateralReserveMint}
|
mint={collateralReserveMint}
|
||||||
onMintChange={setCollateralReserveMint}
|
onMintChange={setCollateralReserveMint}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button type="primary" onClick={onBorrow} disabled={fromAccounts.length === 0}>Borrow</Button>
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={onBorrow}
|
||||||
|
disabled={fromAccounts.length === 0}
|
||||||
|
>
|
||||||
|
Borrow
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Card >;
|
</Card>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -18,13 +18,13 @@ export const CurrentUserBadge = (props: {}) => {
|
||||||
return (
|
return (
|
||||||
<div className="wallet-wrapper">
|
<div className="wallet-wrapper">
|
||||||
<span>
|
<span>
|
||||||
{formatNumber.format(((account?.lamports || 0) / LAMPORTS_PER_SOL))} SOL
|
{formatNumber.format((account?.lamports || 0) / LAMPORTS_PER_SOL)} SOL
|
||||||
</span>
|
</span>
|
||||||
<div className="wallet-key">
|
<div className="wallet-key">
|
||||||
{shortenAddress(`${wallet.publicKey}`)}
|
{shortenAddress(`${wallet.publicKey}`)}
|
||||||
<Identicon
|
<Identicon
|
||||||
address={wallet.publicKey.toBase58()}
|
address={wallet.publicKey?.toBase58()}
|
||||||
style={{ marginLeft: "0.5rem", display: 'flex' }}
|
style={{ marginLeft: "0.5rem", display: "flex" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,31 +1,45 @@
|
||||||
import React, { } from "react";
|
import React from "react";
|
||||||
import { useTokenName, useUserBalance, useCollateralBalance } from './../../hooks';
|
import {
|
||||||
|
useTokenName,
|
||||||
|
useUserBalance,
|
||||||
|
useCollateralBalance,
|
||||||
|
} from "./../../hooks";
|
||||||
import { LendingReserve } from "../../models/lending";
|
import { LendingReserve } from "../../models/lending";
|
||||||
import { formatNumber } from "../../utils/utils";
|
import { formatNumber } from "../../utils/utils";
|
||||||
import { Card } from "antd";
|
import { Card } from "antd";
|
||||||
import './style.less';
|
import "./style.less";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
|
|
||||||
export const DepositInfoLine = (props: {
|
export const DepositInfoLine = (props: {
|
||||||
className?: string,
|
className?: string;
|
||||||
reserve: LendingReserve,
|
reserve: LendingReserve;
|
||||||
address: PublicKey }) => {
|
address: PublicKey;
|
||||||
|
}) => {
|
||||||
const name = useTokenName(props.reserve.liquidityMint);
|
const name = useTokenName(props.reserve.liquidityMint);
|
||||||
const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint);
|
const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint);
|
||||||
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
|
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
|
||||||
|
|
||||||
return <Card className={props.className} bodyStyle={{ display: 'flex', justifyContent: 'space-around', }} >
|
return (
|
||||||
|
<Card
|
||||||
|
className={props.className}
|
||||||
|
bodyStyle={{ display: "flex", justifyContent: "space-around" }}
|
||||||
|
>
|
||||||
<div className="deposit-info-line-item ">
|
<div className="deposit-info-line-item ">
|
||||||
<div>Your balance in Oyster</div>
|
<div>Your balance in Oyster</div>
|
||||||
<div>{formatNumber.format(collateralBalance)} {name}</div>
|
<div>
|
||||||
|
{formatNumber.format(collateralBalance)} {name}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="deposit-info-line-item ">
|
<div className="deposit-info-line-item ">
|
||||||
<div>Your wallet balance</div>
|
<div>Your wallet balance</div>
|
||||||
<div>{formatNumber.format(tokenBalance)} {name}</div>
|
<div>
|
||||||
|
{formatNumber.format(tokenBalance)} {name}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="deposit-info-line-item ">
|
<div className="deposit-info-line-item ">
|
||||||
<div>Health factor</div>
|
<div>Health factor</div>
|
||||||
<div>--</div>
|
<div>--</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -1,19 +1,23 @@
|
||||||
import React, { useCallback, useState } from "react";
|
import React, { useCallback, useState } from "react";
|
||||||
import { useTokenName, useUserBalance } from '../../hooks';
|
import { useTokenName, useUserBalance } from "../../hooks";
|
||||||
import { LendingReserve } from "../../models/lending";
|
import { LendingReserve } from "../../models/lending";
|
||||||
import { TokenIcon } from "../TokenIcon";
|
import { TokenIcon } from "../TokenIcon";
|
||||||
import { Button, Card } from "antd";
|
import { Button, Card } from "antd";
|
||||||
import { NumericInput } from "../Input/numeric";
|
import { NumericInput } from "../Input/numeric";
|
||||||
import { useConnection } from "../../contexts/connection";
|
import { useConnection } from "../../contexts/connection";
|
||||||
import { useWallet } from "../../contexts/wallet";
|
import { useWallet } from "../../contexts/wallet";
|
||||||
import { deposit } from '../../actions/deposit';
|
import { deposit } from "../../actions/deposit";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import './style.less';
|
import "./style.less";
|
||||||
|
|
||||||
export const DepositInput = (props: { className?: string, reserve: LendingReserve, address: PublicKey }) => {
|
export const DepositInput = (props: {
|
||||||
|
className?: string;
|
||||||
|
reserve: LendingReserve;
|
||||||
|
address: PublicKey;
|
||||||
|
}) => {
|
||||||
const connection = useConnection();
|
const connection = useConnection();
|
||||||
const { wallet } = useWallet();
|
const { wallet } = useWallet();
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState("");
|
||||||
|
|
||||||
const reserve = props.reserve;
|
const reserve = props.reserve;
|
||||||
const address = props.address;
|
const address = props.address;
|
||||||
|
@ -29,26 +33,34 @@ export const DepositInput = (props: { className?: string, reserve: LendingReserv
|
||||||
reserve,
|
reserve,
|
||||||
address,
|
address,
|
||||||
connection,
|
connection,
|
||||||
wallet);
|
wallet
|
||||||
}, [value, reserve, fromAccounts, address]);
|
);
|
||||||
|
}, [connection, wallet, value, reserve, fromAccounts, address]);
|
||||||
|
|
||||||
const bodyStyle: React.CSSProperties = {
|
const bodyStyle: React.CSSProperties = {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
height: '100%',
|
height: "100%",
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Card className={props.className} bodyStyle={bodyStyle}>
|
return (
|
||||||
|
<Card className={props.className} bodyStyle={bodyStyle}>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-around' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="deposit-input-title">
|
<div className="deposit-input-title">
|
||||||
How much would you like to deposit?
|
How much would you like to deposit?
|
||||||
</div>
|
</div>
|
||||||
<div className="token-input">
|
<div className="token-input">
|
||||||
<TokenIcon mintAddress={reserve?.liquidityMint} />
|
<TokenIcon mintAddress={reserve?.liquidityMint} />
|
||||||
<NumericInput value={value}
|
<NumericInput
|
||||||
|
value={value}
|
||||||
onChange={(val: any) => {
|
onChange={(val: any) => {
|
||||||
setValue(val);
|
setValue(val);
|
||||||
}}
|
}}
|
||||||
|
@ -64,7 +76,14 @@ export const DepositInput = (props: { className?: string, reserve: LendingReserv
|
||||||
<div>{name}</div>
|
<div>{name}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button type="primary" onClick={onDeposit} disabled={fromAccounts.length === 0}>Deposit</Button>
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={onDeposit}
|
||||||
|
disabled={fromAccounts.length === 0}
|
||||||
|
>
|
||||||
|
Deposit
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Card >;
|
</Card>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -11,13 +11,16 @@ export const Identicon = (props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { style, className } = props;
|
const { style, className } = props;
|
||||||
const address = typeof props.address === 'string' ? props.address : props.address?.toBase58();
|
const address =
|
||||||
|
typeof props.address === "string"
|
||||||
|
? props.address
|
||||||
|
: props.address?.toBase58();
|
||||||
const ref = useRef<HTMLDivElement>();
|
const ref = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (address && ref.current) {
|
if (address && ref.current) {
|
||||||
ref.current.innerHTML = "";
|
ref.current.innerHTML = "";
|
||||||
ref.current.className = props.className || "";
|
ref.current.className = className || "";
|
||||||
ref.current.appendChild(
|
ref.current.appendChild(
|
||||||
Jazzicon(
|
Jazzicon(
|
||||||
style?.width || 16,
|
style?.width || 16,
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import "./../../App.less";
|
import "./../../App.less";
|
||||||
import { Menu } from 'antd';
|
import { Menu } from "antd";
|
||||||
import {
|
import {
|
||||||
PieChartOutlined,
|
PieChartOutlined,
|
||||||
GithubOutlined,
|
GithubOutlined,
|
||||||
BankOutlined,
|
BankOutlined,
|
||||||
LogoutOutlined,
|
LogoutOutlined,
|
||||||
HomeOutlined,
|
HomeOutlined,
|
||||||
RocketOutlined
|
RocketOutlined,
|
||||||
} from '@ant-design/icons';
|
} from "@ant-design/icons";
|
||||||
|
|
||||||
import BasicLayout, { } from '@ant-design/pro-layout';
|
import BasicLayout from "@ant-design/pro-layout";
|
||||||
import { AppBar } from "./../AppBar";
|
import { AppBar } from "./../AppBar";
|
||||||
import { Link, useLocation } from "react-router-dom";
|
import { Link, useLocation } from "react-router-dom";
|
||||||
import { useConnectionConfig } from "../../contexts/connection";
|
import { useConnectionConfig } from "../../contexts/connection";
|
||||||
|
@ -19,16 +19,17 @@ export const AppLayout = (props: any) => {
|
||||||
const { env } = useConnectionConfig();
|
const { env } = useConnectionConfig();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
console.log(location.pathname)
|
console.log(location.pathname);
|
||||||
const paths: { [key: string]: string } = {
|
const paths: { [key: string]: string } = {
|
||||||
'/dashboard': '2',
|
"/dashboard": "2",
|
||||||
'/deposit': '3',
|
"/deposit": "3",
|
||||||
'/borrow': '4',
|
"/borrow": "4",
|
||||||
'/faucet': '4',
|
"/faucet": "4",
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const current = [...Object.keys(paths)].find(key => location.pathname.startsWith(key)) || '';
|
const current =
|
||||||
|
[...Object.keys(paths)].find((key) => location.pathname.startsWith(key)) ||
|
||||||
|
"";
|
||||||
const defaultKey = paths[current] || "1";
|
const defaultKey = paths[current] || "1";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -38,7 +39,8 @@ export const AppLayout = (props: any) => {
|
||||||
Oyster Lending is unaudited software. Use at your own risk.
|
Oyster Lending is unaudited software. Use at your own risk.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<BasicLayout title="Oyster Lending"
|
<BasicLayout
|
||||||
|
title="Oyster Lending"
|
||||||
navTheme="realDark"
|
navTheme="realDark"
|
||||||
headerTheme="dark"
|
headerTheme="dark"
|
||||||
theme="dark"
|
theme="dark"
|
||||||
|
@ -47,10 +49,13 @@ export const AppLayout = (props: any) => {
|
||||||
logo={<div className="App-logo" />}
|
logo={<div className="App-logo" />}
|
||||||
rightContentRender={() => <AppBar />}
|
rightContentRender={() => <AppBar />}
|
||||||
links={[
|
links={[
|
||||||
<div title="Fork"><GithubOutlined /></div>
|
<div title="Fork">
|
||||||
|
<GithubOutlined />
|
||||||
|
</div>,
|
||||||
]}
|
]}
|
||||||
menuContentRender={() => {
|
menuContentRender={() => {
|
||||||
return <Menu theme="dark" defaultSelectedKeys={[defaultKey]} mode="inline">
|
return (
|
||||||
|
<Menu theme="dark" defaultSelectedKeys={[defaultKey]} mode="inline">
|
||||||
<Menu.Item key="1" icon={<HomeOutlined />}>
|
<Menu.Item key="1" icon={<HomeOutlined />}>
|
||||||
<Link
|
<Link
|
||||||
to={{
|
to={{
|
||||||
|
@ -60,7 +65,7 @@ export const AppLayout = (props: any) => {
|
||||||
Home
|
Home
|
||||||
</Link>
|
</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item key="2" icon={<PieChartOutlined />} >
|
<Menu.Item key="2" icon={<PieChartOutlined />}>
|
||||||
<Link
|
<Link
|
||||||
to={{
|
to={{
|
||||||
pathname: "/dashboard",
|
pathname: "/dashboard",
|
||||||
|
@ -87,7 +92,8 @@ export const AppLayout = (props: any) => {
|
||||||
Borrow
|
Borrow
|
||||||
</Link>
|
</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
{env !== "mainnet-beta" && <Menu.Item key="5" icon={<RocketOutlined />}>
|
{env !== "mainnet-beta" && (
|
||||||
|
<Menu.Item key="5" icon={<RocketOutlined />}>
|
||||||
<Link
|
<Link
|
||||||
to={{
|
to={{
|
||||||
pathname: "/faucet",
|
pathname: "/faucet",
|
||||||
|
@ -95,13 +101,14 @@ export const AppLayout = (props: any) => {
|
||||||
>
|
>
|
||||||
Faucet
|
Faucet
|
||||||
</Link>
|
</Link>
|
||||||
</Menu.Item>}
|
</Menu.Item>
|
||||||
|
)}
|
||||||
</Menu>
|
</Menu>
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</BasicLayout>
|
</BasicLayout>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,35 @@
|
||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
import { LendingReserve } from "../../models/lending";
|
import { LendingReserve } from "../../models/lending";
|
||||||
import { Card } from "antd";
|
import { Card } from "antd";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import './style.less';
|
import "./style.less";
|
||||||
|
|
||||||
export const ReserveStatus = (props: { className?: string, reserve: LendingReserve, address: PublicKey }) => {
|
|
||||||
const [] = useState('');
|
|
||||||
|
|
||||||
|
export const ReserveStatus = (props: {
|
||||||
|
className?: string;
|
||||||
|
reserve: LendingReserve;
|
||||||
|
address: PublicKey;
|
||||||
|
}) => {
|
||||||
const bodyStyle: React.CSSProperties = {
|
const bodyStyle: React.CSSProperties = {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
alignItems: 'center'
|
alignItems: "center",
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Card className={props.className}
|
return (
|
||||||
title={
|
<Card
|
||||||
<>Reserve Status & Configuration</>
|
className={props.className}
|
||||||
}
|
title={<>Reserve Status & Configuration</>}
|
||||||
bodyStyle={bodyStyle}>
|
bodyStyle={bodyStyle}
|
||||||
|
>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-around' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
}}
|
||||||
|
>
|
||||||
TODO: Reserve Status - add chart
|
TODO: Reserve Status - add chart
|
||||||
</div>
|
</div>
|
||||||
</Card >;
|
</Card>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTokenName } from './../../hooks';
|
import { useTokenName } from "./../../hooks";
|
||||||
import { LendingReserve } from "../../models/lending";
|
import { LendingReserve } from "../../models/lending";
|
||||||
import { TokenIcon } from "../../components/TokenIcon";
|
import { TokenIcon } from "../../components/TokenIcon";
|
||||||
import { formatNumber, formatPct, fromLamports } from "../../utils/utils";
|
import { formatNumber, formatPct, fromLamports } from "../../utils/utils";
|
||||||
|
@ -10,22 +10,25 @@ import { PublicKey } from "@solana/web3.js";
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
export enum SideReserveOverviewMode {
|
export enum SideReserveOverviewMode {
|
||||||
Deposit = 'deposit',
|
Deposit = "deposit",
|
||||||
Borrow = 'borrow'
|
Borrow = "borrow",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SideReserveOverview = (props: {
|
export const SideReserveOverview = (props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
reserve: LendingReserve,
|
reserve: LendingReserve;
|
||||||
address: PublicKey,
|
address: PublicKey;
|
||||||
mode: SideReserveOverviewMode
|
mode: SideReserveOverviewMode;
|
||||||
}) => {
|
}) => {
|
||||||
const reserve = props.reserve;
|
const reserve = props.reserve;
|
||||||
const mode = props.mode;
|
const mode = props.mode;
|
||||||
const name = useTokenName(reserve?.liquidityMint);
|
const name = useTokenName(reserve?.liquidityMint);
|
||||||
const liquidityMint = useMint(props.reserve.liquidityMint);
|
const liquidityMint = useMint(props.reserve.liquidityMint);
|
||||||
|
|
||||||
const totalLiquidity = fromLamports(props.reserve.totalLiquidity.toNumber(), liquidityMint);
|
const totalLiquidity = fromLamports(
|
||||||
|
props.reserve.totalLiquidity.toNumber(),
|
||||||
|
liquidityMint
|
||||||
|
);
|
||||||
|
|
||||||
// TODO: calculate
|
// TODO: calculate
|
||||||
const depositApy = 0.048;
|
const depositApy = 0.048;
|
||||||
|
@ -38,24 +41,20 @@ export const SideReserveOverview = (props: {
|
||||||
|
|
||||||
let extraInfo: JSX.Element | null = null;
|
let extraInfo: JSX.Element | null = null;
|
||||||
if (mode === SideReserveOverviewMode.Deposit) {
|
if (mode === SideReserveOverviewMode.Deposit) {
|
||||||
|
extraInfo = (
|
||||||
extraInfo = <>
|
<>
|
||||||
<div className="card-row">
|
<div className="card-row">
|
||||||
<Text type="secondary" className="card-cell ">
|
<Text type="secondary" className="card-cell ">
|
||||||
Deposit APY:
|
Deposit APY:
|
||||||
</Text>
|
</Text>
|
||||||
<div className="card-cell ">
|
<div className="card-cell ">{formatPct.format(depositApy)}</div>
|
||||||
{formatPct.format(depositApy)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card-row">
|
<div className="card-row">
|
||||||
<Text type="secondary" className="card-cell ">
|
<Text type="secondary" className="card-cell ">
|
||||||
Maxiumum LTV:
|
Maxiumum LTV:
|
||||||
</Text>
|
</Text>
|
||||||
<div className="card-cell ">
|
<div className="card-cell ">{formatPct.format(maxLTV)}</div>
|
||||||
{formatPct.format(maxLTV)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card-row">
|
<div className="card-row">
|
||||||
|
@ -75,32 +74,46 @@ export const SideReserveOverview = (props: {
|
||||||
{formatPct.format(liquidiationPenalty)}
|
{formatPct.format(liquidiationPenalty)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>;
|
</>
|
||||||
|
);
|
||||||
} else if (mode === SideReserveOverviewMode.Borrow) {
|
} else if (mode === SideReserveOverviewMode.Borrow) {
|
||||||
extraInfo = <>
|
extraInfo = (
|
||||||
|
<>
|
||||||
<div className="card-row">
|
<div className="card-row">
|
||||||
<Text type="secondary" className="card-cell ">
|
<Text type="secondary" className="card-cell ">
|
||||||
Borrow APY:
|
Borrow APY:
|
||||||
</Text>
|
</Text>
|
||||||
<div className="card-cell ">
|
<div className="card-cell ">{formatPct.format(borrowApy)}</div>
|
||||||
{formatPct.format(borrowApy)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
</>;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Card className={props.className} title={
|
return (
|
||||||
<div style={{ display: 'flex', alignItems: 'center', fontSize: '1.2rem', justifyContent: 'center' }}>
|
<Card
|
||||||
<TokenIcon mintAddress={reserve?.liquidityMint} style={{ width: 30, height: 30 }} /> {name} Reserve Overview
|
className={props.className}
|
||||||
|
title={
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
fontSize: "1.2rem",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TokenIcon
|
||||||
|
mintAddress={reserve?.liquidityMint}
|
||||||
|
style={{ width: 30, height: 30 }}
|
||||||
|
/>{" "}
|
||||||
|
{name} Reserve Overview
|
||||||
</div>
|
</div>
|
||||||
}>
|
}
|
||||||
|
>
|
||||||
<div className="card-row">
|
<div className="card-row">
|
||||||
<Text type="secondary" className="card-cell ">
|
<Text type="secondary" className="card-cell ">
|
||||||
Utilization rate:
|
Utilization rate:
|
||||||
</Text>
|
</Text>
|
||||||
<div className="card-cell ">
|
<div className="card-cell ">{formatPct.format(utilizationRate)}</div>
|
||||||
{formatPct.format(utilizationRate)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card-row">
|
<div className="card-row">
|
||||||
|
@ -113,5 +126,6 @@ export const SideReserveOverview = (props: {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{extraInfo}
|
{extraInfo}
|
||||||
</Card>;
|
</Card>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -18,8 +18,8 @@ export const TokenIcon = (props: {
|
||||||
alt="Token icon"
|
alt="Token icon"
|
||||||
className={props.className}
|
className={props.className}
|
||||||
key={icon}
|
key={icon}
|
||||||
width={props.style?.width || '20'}
|
width={props.style?.width || "20"}
|
||||||
height={props.style?.height || '20'}
|
height={props.style?.height || "20"}
|
||||||
src={icon}
|
src={icon}
|
||||||
style={{
|
style={{
|
||||||
marginRight: "0.5rem",
|
marginRight: "0.5rem",
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useCollateralBalance, useTokenName, useUserBalance } from './../../hooks';
|
import {
|
||||||
|
useCollateralBalance,
|
||||||
|
useTokenName,
|
||||||
|
useUserBalance,
|
||||||
|
} from "./../../hooks";
|
||||||
import { LendingReserve } from "../../models/lending";
|
import { LendingReserve } from "../../models/lending";
|
||||||
import { formatNumber } from "../../utils/utils";
|
import { formatNumber } from "../../utils/utils";
|
||||||
import { Button, Card, Typography } from "antd";
|
import { Button, Card, Typography } from "antd";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useMint } from "../../contexts/accounts";
|
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
export const UserLendingCard = (props: {
|
export const UserLendingCard = (props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
reserve: LendingReserve,
|
reserve: LendingReserve;
|
||||||
address: PublicKey,
|
address: PublicKey;
|
||||||
}) => {
|
}) => {
|
||||||
const reserve = props.reserve;
|
const reserve = props.reserve;
|
||||||
const address = props.address;
|
const address = props.address;
|
||||||
|
@ -22,19 +25,28 @@ export const UserLendingCard = (props: {
|
||||||
const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint);
|
const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint);
|
||||||
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
|
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
|
||||||
|
|
||||||
|
|
||||||
// TODO: calculate
|
// TODO: calculate
|
||||||
const borrowed = 0;
|
const borrowed = 0;
|
||||||
const healthFactor = '--';
|
const healthFactor = "--";
|
||||||
const ltv = 0;
|
const ltv = 0;
|
||||||
const available = 0;
|
const available = 0;
|
||||||
|
|
||||||
|
return (
|
||||||
return <Card className={props.className} title={
|
<Card
|
||||||
<div style={{ display: 'flex', alignItems: 'center', fontSize: '1.2rem', justifyContent: 'center' }}>
|
className={props.className}
|
||||||
|
title={
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
fontSize: "1.2rem",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
Your Information
|
Your Information
|
||||||
</div>
|
</div>
|
||||||
}>
|
}
|
||||||
|
>
|
||||||
<h3>Borrows</h3>
|
<h3>Borrows</h3>
|
||||||
|
|
||||||
<div className="card-row">
|
<div className="card-row">
|
||||||
|
@ -50,18 +62,14 @@ export const UserLendingCard = (props: {
|
||||||
<Text type="secondary" className="card-cell ">
|
<Text type="secondary" className="card-cell ">
|
||||||
Health factor:
|
Health factor:
|
||||||
</Text>
|
</Text>
|
||||||
<div className="card-cell ">
|
<div className="card-cell ">{healthFactor}</div>
|
||||||
{healthFactor}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card-row">
|
<div className="card-row">
|
||||||
<Text type="secondary" className="card-cell ">
|
<Text type="secondary" className="card-cell ">
|
||||||
Loan to value:
|
Loan to value:
|
||||||
</Text>
|
</Text>
|
||||||
<div className="card-cell ">
|
<div className="card-cell ">{formatNumber.format(ltv)}</div>
|
||||||
{formatNumber.format(ltv)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card-row">
|
<div className="card-row">
|
||||||
|
@ -93,7 +101,10 @@ export const UserLendingCard = (props: {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card-row" style={{ marginTop: 20, justifyContent: 'space-evenly' }}>
|
<div
|
||||||
|
className="card-row"
|
||||||
|
style={{ marginTop: 20, justifyContent: "space-evenly" }}
|
||||||
|
>
|
||||||
<Link to={`/deposit/${address}`}>
|
<Link to={`/deposit/${address}`}>
|
||||||
<Button>Deposit</Button>
|
<Button>Deposit</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -107,7 +118,6 @@ export const UserLendingCard = (props: {
|
||||||
<Button disabled={true}>Repay</Button>
|
<Button disabled={true}>Repay</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
</Card>;
|
};
|
||||||
}
|
|
||||||
|
|
|
@ -1,30 +1,39 @@
|
||||||
import React, { useCallback, useState } from "react";
|
import React, { useCallback, useState } from "react";
|
||||||
import { useCollateralBalance, useTokenName, useUserBalance } from '../../hooks';
|
import {
|
||||||
|
useCollateralBalance,
|
||||||
|
useTokenName,
|
||||||
|
useUserBalance,
|
||||||
|
} from "../../hooks";
|
||||||
import { LendingReserve } from "../../models/lending";
|
import { LendingReserve } from "../../models/lending";
|
||||||
import { TokenIcon } from "../TokenIcon";
|
import { TokenIcon } from "../TokenIcon";
|
||||||
import { Button, Card } from "antd";
|
import { Button, Card } from "antd";
|
||||||
import { NumericInput } from "../Input/numeric";
|
import { NumericInput } from "../Input/numeric";
|
||||||
import { useConnection } from "../../contexts/connection";
|
import { useConnection } from "../../contexts/connection";
|
||||||
import { useWallet } from "../../contexts/wallet";
|
import { useWallet } from "../../contexts/wallet";
|
||||||
import { withdraw } from '../../actions';
|
import { withdraw } from "../../actions";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import './style.less';
|
import "./style.less";
|
||||||
import { useMint } from "../../contexts/accounts";
|
|
||||||
|
|
||||||
export const WithdrawInput = (props: { className?: string, reserve: LendingReserve, address: PublicKey }) => {
|
export const WithdrawInput = (props: {
|
||||||
|
className?: string;
|
||||||
|
reserve: LendingReserve;
|
||||||
|
address: PublicKey;
|
||||||
|
}) => {
|
||||||
const connection = useConnection();
|
const connection = useConnection();
|
||||||
const { wallet } = useWallet();
|
const { wallet } = useWallet();
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState("");
|
||||||
|
|
||||||
const reserve = props.reserve;
|
const reserve = props.reserve;
|
||||||
const address = props.address;
|
const address = props.address;
|
||||||
|
|
||||||
const liquidityMint = useMint(reserve?.liquidityMint);
|
|
||||||
const name = useTokenName(reserve?.liquidityMint);
|
const name = useTokenName(reserve?.liquidityMint);
|
||||||
const { balanceLamports: collateralBalanceLamports, accounts: fromAccounts } = useUserBalance(reserve?.collateralMint);
|
|
||||||
const {
|
const {
|
||||||
balance: collateralBalanceInLiquidity
|
balanceLamports: collateralBalanceLamports,
|
||||||
} = useCollateralBalance(reserve);
|
accounts: fromAccounts,
|
||||||
|
} = useUserBalance(reserve?.collateralMint);
|
||||||
|
const { balance: collateralBalanceInLiquidity } = useCollateralBalance(
|
||||||
|
reserve
|
||||||
|
);
|
||||||
|
|
||||||
const onWithdraw = useCallback(() => {
|
const onWithdraw = useCallback(() => {
|
||||||
withdraw(
|
withdraw(
|
||||||
|
@ -36,26 +45,43 @@ export const WithdrawInput = (props: { className?: string, reserve: LendingReser
|
||||||
reserve,
|
reserve,
|
||||||
address,
|
address,
|
||||||
connection,
|
connection,
|
||||||
wallet);
|
wallet
|
||||||
}, [value, reserve, fromAccounts, address, liquidityMint]);
|
);
|
||||||
|
}, [
|
||||||
|
connection,
|
||||||
|
wallet,
|
||||||
|
collateralBalanceLamports,
|
||||||
|
collateralBalanceInLiquidity,
|
||||||
|
value,
|
||||||
|
reserve,
|
||||||
|
fromAccounts,
|
||||||
|
address,
|
||||||
|
]);
|
||||||
|
|
||||||
const bodyStyle: React.CSSProperties = {
|
const bodyStyle: React.CSSProperties = {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
height: '100%',
|
height: "100%",
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Card className={props.className} bodyStyle={bodyStyle}>
|
return (
|
||||||
|
<Card className={props.className} bodyStyle={bodyStyle}>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-around' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="withdraw-input-title">
|
<div className="withdraw-input-title">
|
||||||
How much would you like to withdraw?
|
How much would you like to withdraw?
|
||||||
</div>
|
</div>
|
||||||
<div className="token-input">
|
<div className="token-input">
|
||||||
<TokenIcon mintAddress={reserve?.liquidityMint} />
|
<TokenIcon mintAddress={reserve?.liquidityMint} />
|
||||||
<NumericInput value={value}
|
<NumericInput
|
||||||
|
value={value}
|
||||||
onChange={(val: any) => {
|
onChange={(val: any) => {
|
||||||
setValue(val);
|
setValue(val);
|
||||||
}}
|
}}
|
||||||
|
@ -71,7 +97,14 @@ export const WithdrawInput = (props: { className?: string, reserve: LendingReser
|
||||||
<div>{name}</div>
|
<div>{name}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button type="primary" onClick={onWithdraw} disabled={fromAccounts.length === 0}>Withdraw</Button>
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={onWithdraw}
|
||||||
|
disabled={fromAccounts.length === 0}
|
||||||
|
>
|
||||||
|
Withdraw
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Card >;
|
</Card>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useConnection } from "./connection";
|
||||||
import { useWallet } from "./wallet";
|
import { useWallet } from "./wallet";
|
||||||
import { AccountInfo, Connection, PublicKey } from "@solana/web3.js";
|
import { AccountInfo, Connection, PublicKey } from "@solana/web3.js";
|
||||||
import { programIds, WRAPPED_SOL_MINT } from "./../constants/ids";
|
import { programIds, WRAPPED_SOL_MINT } from "./../constants/ids";
|
||||||
import { AccountLayout, u64, MintInfo, MintLayout, Token } from "@solana/spl-token";
|
import { AccountLayout, u64, MintInfo, MintLayout } from "@solana/spl-token";
|
||||||
import { TokenAccount } from "./../models";
|
import { TokenAccount } from "./../models";
|
||||||
import { chunks } from "./../utils/utils";
|
import { chunks } from "./../utils/utils";
|
||||||
import { EventEmitter } from "./../utils/eventEmitter";
|
import { EventEmitter } from "./../utils/eventEmitter";
|
||||||
|
@ -46,7 +46,10 @@ export const MintParser = (pubKey: PublicKey, info: AccountInfo<Buffer>) => {
|
||||||
return details;
|
return details;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TokenAccountParser = (pubKey: PublicKey, info: AccountInfo<Buffer>) => {
|
export const TokenAccountParser = (
|
||||||
|
pubKey: PublicKey,
|
||||||
|
info: AccountInfo<Buffer>
|
||||||
|
) => {
|
||||||
const buffer = Buffer.from(info.data);
|
const buffer = Buffer.from(info.data);
|
||||||
const data = deserializeAccount(buffer);
|
const data = deserializeAccount(buffer);
|
||||||
|
|
||||||
|
@ -118,8 +121,12 @@ export const cache = {
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
},
|
},
|
||||||
add: (id: PublicKey | string, obj: AccountInfo<Buffer>, parser?: AccountParser) => {
|
add: (
|
||||||
const address = typeof id === 'string' ? id : id?.toBase58();
|
id: PublicKey | string,
|
||||||
|
obj: AccountInfo<Buffer>,
|
||||||
|
parser?: AccountParser
|
||||||
|
) => {
|
||||||
|
const address = typeof id === "string" ? id : id?.toBase58();
|
||||||
const deserialize = parser ? parser : keyToAccountParser.get(address);
|
const deserialize = parser ? parser : keyToAccountParser.get(address);
|
||||||
if (!deserialize) {
|
if (!deserialize) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -160,7 +167,7 @@ export const cache = {
|
||||||
},
|
},
|
||||||
registerParser: (pubkey: PublicKey | string, parser: AccountParser) => {
|
registerParser: (pubkey: PublicKey | string, parser: AccountParser) => {
|
||||||
if (pubkey) {
|
if (pubkey) {
|
||||||
const address = typeof pubkey === 'string' ? pubkey : pubkey?.toBase58();
|
const address = typeof pubkey === "string" ? pubkey : pubkey?.toBase58();
|
||||||
keyToAccountParser.set(address, parser);
|
keyToAccountParser.set(address, parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +179,7 @@ export const useAccountsContext = () => {
|
||||||
const context = useContext(AccountsContext);
|
const context = useContext(AccountsContext);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
};
|
||||||
|
|
||||||
function wrapNativeAccount(
|
function wrapNativeAccount(
|
||||||
pubkey: PublicKey,
|
pubkey: PublicKey,
|
||||||
|
@ -206,13 +213,16 @@ const UseNativeAccount = () => {
|
||||||
|
|
||||||
const [nativeAccount, setNativeAccount] = useState<AccountInfo<Buffer>>();
|
const [nativeAccount, setNativeAccount] = useState<AccountInfo<Buffer>>();
|
||||||
|
|
||||||
const updateCache = useCallback((account) => {
|
const updateCache = useCallback(
|
||||||
|
(account) => {
|
||||||
const wrapped = wrapNativeAccount(wallet.publicKey, account);
|
const wrapped = wrapNativeAccount(wallet.publicKey, account);
|
||||||
if (wrapped !== undefined && wallet) {
|
if (wrapped !== undefined && wallet) {
|
||||||
cache.registerParser(wallet.publicKey.toBase58(), TokenAccountParser);
|
cache.registerParser(wallet.publicKey?.toBase58(), TokenAccountParser);
|
||||||
genericCache.set(wallet.publicKey.toBase58(), wrapped as TokenAccount);
|
genericCache.set(wallet.publicKey?.toBase58(), wrapped as TokenAccount);
|
||||||
}
|
}
|
||||||
}, [wallet]);
|
},
|
||||||
|
[wallet]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!connection || !wallet?.publicKey) {
|
if (!connection || !wallet?.publicKey) {
|
||||||
|
@ -231,7 +241,7 @@ const UseNativeAccount = () => {
|
||||||
setNativeAccount(acc);
|
setNativeAccount(acc);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [setNativeAccount, wallet, wallet.publicKey, connection]);
|
}, [setNativeAccount, wallet, wallet.publicKey, connection, updateCache]);
|
||||||
|
|
||||||
return { nativeAccount };
|
return { nativeAccount };
|
||||||
};
|
};
|
||||||
|
@ -252,8 +262,7 @@ const precacheUserTokenAccounts = async (
|
||||||
const accounts = await connection.getTokenAccountsByOwner(owner, {
|
const accounts = await connection.getTokenAccountsByOwner(owner, {
|
||||||
programId: programIds().token,
|
programId: programIds().token,
|
||||||
});
|
});
|
||||||
accounts.value
|
accounts.value.forEach((info) => {
|
||||||
.forEach((info) => {
|
|
||||||
cache.add(info.pubkey.toBase58(), info.account, TokenAccountParser);
|
cache.add(info.pubkey.toBase58(), info.account, TokenAccountParser);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -266,15 +275,21 @@ export function AccountsProvider({ children = null as any }) {
|
||||||
const { nativeAccount } = UseNativeAccount();
|
const { nativeAccount } = UseNativeAccount();
|
||||||
|
|
||||||
const selectUserAccounts = useCallback(() => {
|
const selectUserAccounts = useCallback(() => {
|
||||||
return cache.byParser(TokenAccountParser).map(id => cache.get(id)).filter(
|
return cache
|
||||||
(a) => a && a.info.owner.toBase58() === wallet.publicKey.toBase58()
|
.byParser(TokenAccountParser)
|
||||||
).map(a => a as TokenAccount);
|
.map((id) => cache.get(id))
|
||||||
|
.filter(
|
||||||
|
(a) => a && a.info.owner.toBase58() === wallet.publicKey?.toBase58()
|
||||||
|
)
|
||||||
|
.map((a) => a as TokenAccount);
|
||||||
}, [wallet]);
|
}, [wallet]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const accounts = selectUserAccounts().filter((a) => a !== undefined) as TokenAccount[];
|
const accounts = selectUserAccounts().filter(
|
||||||
|
(a) => a !== undefined
|
||||||
|
) as TokenAccount[];
|
||||||
setUserAccounts(accounts);
|
setUserAccounts(accounts);
|
||||||
}, [nativeAccount, wallet, tokenAccounts]);
|
}, [nativeAccount, wallet, tokenAccounts, selectUserAccounts]);
|
||||||
|
|
||||||
const publicKey = wallet?.publicKey;
|
const publicKey = wallet?.publicKey;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -296,10 +311,7 @@ export function AccountsProvider({ children = null as any }) {
|
||||||
if (info.accountInfo.data.length === AccountLayout.span) {
|
if (info.accountInfo.data.length === AccountLayout.span) {
|
||||||
const data = deserializeAccount(info.accountInfo.data);
|
const data = deserializeAccount(info.accountInfo.data);
|
||||||
|
|
||||||
if (
|
if (PRECACHED_OWNERS.has(data.owner.toBase58()) || !cache.get(id)) {
|
||||||
PRECACHED_OWNERS.has(data.owner.toBase58()) ||
|
|
||||||
!cache.get(id)
|
|
||||||
) {
|
|
||||||
cache.add(id, info.accountInfo, TokenAccountParser);
|
cache.add(id, info.accountInfo, TokenAccountParser);
|
||||||
setTokenAccounts(selectUserAccounts());
|
setTokenAccounts(selectUserAccounts());
|
||||||
accountEmitter.raiseAccountUpdated(id);
|
accountEmitter.raiseAccountUpdated(id);
|
||||||
|
@ -359,7 +371,8 @@ export const getMultipleAccounts = async (
|
||||||
const array = result
|
const array = result
|
||||||
.map(
|
.map(
|
||||||
(a) =>
|
(a) =>
|
||||||
a.array.map((acc) => {
|
a.array
|
||||||
|
.map((acc) => {
|
||||||
if (!acc) {
|
if (!acc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -370,7 +383,8 @@ export const getMultipleAccounts = async (
|
||||||
data: Buffer.from(data[0], "base64"),
|
data: Buffer.from(data[0], "base64"),
|
||||||
} as AccountInfo<Buffer>;
|
} as AccountInfo<Buffer>;
|
||||||
return obj;
|
return obj;
|
||||||
}).filter(_ => _) as AccountInfo<Buffer>[]
|
})
|
||||||
|
.filter((_) => _) as AccountInfo<Buffer>[]
|
||||||
)
|
)
|
||||||
.flat();
|
.flat();
|
||||||
return { keys, array };
|
return { keys, array };
|
||||||
|
@ -412,15 +426,15 @@ export function useMint(key?: string | PublicKey) {
|
||||||
|
|
||||||
cache
|
cache
|
||||||
.query(connection, id, MintParser)
|
.query(connection, id, MintParser)
|
||||||
.then(acc => setMint(acc.info as any))
|
.then((acc) => setMint(acc.info as any))
|
||||||
.catch((err) =>
|
.catch((err) => console.log(err));
|
||||||
console.log(err)
|
|
||||||
);
|
|
||||||
|
|
||||||
const dispose = cache.emitter.onCache((e) => {
|
const dispose = cache.emitter.onCache((e) => {
|
||||||
const event = e;
|
const event = e;
|
||||||
if (event.id === id) {
|
if (event.id === id) {
|
||||||
cache.query(connection, id, MintParser).then(mint => setMint(mint.info as any));
|
cache
|
||||||
|
.query(connection, id, MintParser)
|
||||||
|
.then((mint) => setMint(mint.info as any));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -443,9 +457,9 @@ export function useAccount(pubKey?: PublicKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const acc = await cache.query(connection, key, TokenAccountParser).catch((err) =>
|
const acc = await cache
|
||||||
console.log(err)
|
.query(connection, key, TokenAccountParser)
|
||||||
);
|
.catch((err) => console.log(err));
|
||||||
if (acc) {
|
if (acc) {
|
||||||
setAccount(acc);
|
setAccount(acc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,18 @@ import React, { useContext, useEffect, useMemo, useState } from "react";
|
||||||
import { setProgramIds } from "./../constants/ids";
|
import { setProgramIds } from "./../constants/ids";
|
||||||
import { notify } from "./../utils/notifications";
|
import { notify } from "./../utils/notifications";
|
||||||
import { ExplorerLink } from "../components/ExplorerLink";
|
import { ExplorerLink } from "../components/ExplorerLink";
|
||||||
import LocalTokens from '../config/tokens.json';
|
import LocalTokens from "../config/tokens.json";
|
||||||
|
|
||||||
export type ENV = "mainnet-beta" | "testnet" | "devnet" | "localnet" | "lending";
|
export type ENV =
|
||||||
|
| "mainnet-beta"
|
||||||
|
| "testnet"
|
||||||
|
| "devnet"
|
||||||
|
| "localnet"
|
||||||
|
| "lending";
|
||||||
|
|
||||||
export const ENDPOINTS = [
|
export const ENDPOINTS = [
|
||||||
{
|
{
|
||||||
name: 'lending' as ENV,
|
name: "lending" as ENV,
|
||||||
endpoint: "https://tln.solana.com",
|
endpoint: "https://tln.solana.com",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -88,7 +93,7 @@ export function ConnectionProvider({ children = undefined as any }) {
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch(err => [])
|
.catch((err) => [])
|
||||||
.then((list: KnownToken[]) => {
|
.then((list: KnownToken[]) => {
|
||||||
const knownMints = [...LocalTokens, ...list].reduce((map, item) => {
|
const knownMints = [...LocalTokens, ...list].reduce((map, item) => {
|
||||||
map.set(item.mintAddress, item);
|
map.set(item.mintAddress, item);
|
||||||
|
|
|
@ -1,14 +1,23 @@
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import { useConnection } from "./connection";
|
import { useConnection } from "./connection";
|
||||||
import { LENDING_PROGRAM_ID } from "./../constants/ids";
|
import { LENDING_PROGRAM_ID } from "./../constants/ids";
|
||||||
import { LendingMarketParser, isLendingReserve, isLendingMarket, LendingReserveParser, LendingReserve } from "./../models/lending";
|
import {
|
||||||
import { cache, getMultipleAccounts, MintParser, ParsedAccount } from "./accounts";
|
LendingMarketParser,
|
||||||
|
isLendingReserve,
|
||||||
|
isLendingMarket,
|
||||||
|
LendingReserveParser,
|
||||||
|
LendingReserve,
|
||||||
|
} from "./../models/lending";
|
||||||
|
import {
|
||||||
|
cache,
|
||||||
|
getMultipleAccounts,
|
||||||
|
MintParser,
|
||||||
|
ParsedAccount,
|
||||||
|
} from "./accounts";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import { DexMarketParser } from "../models/dex";
|
import { DexMarketParser } from "../models/dex";
|
||||||
|
|
||||||
export interface LendingContextState {
|
export interface LendingContextState {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const LendingContext = React.createContext<LendingContextState | null>(null);
|
const LendingContext = React.createContext<LendingContextState | null>(null);
|
||||||
|
|
||||||
|
@ -17,14 +26,13 @@ export function LendingProvider({ children = null as any }) {
|
||||||
return (
|
return (
|
||||||
<LendingContext.Provider
|
<LendingContext.Provider
|
||||||
value={{
|
value={{
|
||||||
accounts
|
accounts,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</LendingContext.Provider>
|
</LendingContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
export const useLending = () => {
|
export const useLending = () => {
|
||||||
const connection = useConnection();
|
const connection = useConnection();
|
||||||
|
@ -32,9 +40,17 @@ export const useLending = () => {
|
||||||
|
|
||||||
const processAccount = useCallback((item) => {
|
const processAccount = useCallback((item) => {
|
||||||
if (isLendingReserve(item.account)) {
|
if (isLendingReserve(item.account)) {
|
||||||
return cache.add(item.pubkey.toBase58(), item.account, LendingReserveParser);
|
return cache.add(
|
||||||
|
item.pubkey.toBase58(),
|
||||||
|
item.account,
|
||||||
|
LendingReserveParser
|
||||||
|
);
|
||||||
} else if (isLendingMarket(item.account)) {
|
} else if (isLendingMarket(item.account)) {
|
||||||
return cache.add(item.pubkey.toBase58(), item.account, LendingMarketParser);
|
return cache.add(
|
||||||
|
item.pubkey.toBase58(),
|
||||||
|
item.account,
|
||||||
|
LendingMarketParser
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -45,20 +61,32 @@ export const useLending = () => {
|
||||||
const queryLendingAccounts = async () => {
|
const queryLendingAccounts = async () => {
|
||||||
const accounts = (await connection.getProgramAccounts(LENDING_PROGRAM_ID))
|
const accounts = (await connection.getProgramAccounts(LENDING_PROGRAM_ID))
|
||||||
.map(processAccount)
|
.map(processAccount)
|
||||||
.filter(item => item !== undefined);
|
.filter((item) => item !== undefined);
|
||||||
|
|
||||||
const toQuery = [
|
const toQuery = [
|
||||||
...accounts.filter(acc => (acc?.info as LendingReserve).lendingMarket !== undefined)
|
...accounts
|
||||||
.map(acc => acc as ParsedAccount<LendingReserve>)
|
.filter(
|
||||||
.map(acc => {
|
(acc) => (acc?.info as LendingReserve).lendingMarket !== undefined
|
||||||
|
)
|
||||||
|
.map((acc) => acc as ParsedAccount<LendingReserve>)
|
||||||
|
.map((acc) => {
|
||||||
const result = [
|
const result = [
|
||||||
cache.registerParser(acc?.info.collateralMint.toBase58(), MintParser),
|
cache.registerParser(
|
||||||
cache.registerParser(acc?.info.liquidityMint.toBase58(), MintParser),
|
acc?.info.collateralMint.toBase58(),
|
||||||
|
MintParser
|
||||||
|
),
|
||||||
|
cache.registerParser(
|
||||||
|
acc?.info.liquidityMint.toBase58(),
|
||||||
|
MintParser
|
||||||
|
),
|
||||||
// ignore dex if its not set
|
// ignore dex if its not set
|
||||||
cache.registerParser(acc?.info.dexMarketOption ? acc?.info.dexMarket.toBase58() : '', DexMarketParser),
|
cache.registerParser(
|
||||||
].filter(_ => _);
|
acc?.info.dexMarketOption ? acc?.info.dexMarket.toBase58() : "",
|
||||||
|
DexMarketParser
|
||||||
|
),
|
||||||
|
].filter((_) => _);
|
||||||
return result;
|
return result;
|
||||||
})
|
}),
|
||||||
].flat() as string[];
|
].flat() as string[];
|
||||||
|
|
||||||
// This will pre-cache all accounts used by pools
|
// This will pre-cache all accounts used by pools
|
||||||
|
@ -76,12 +104,10 @@ export const useLending = () => {
|
||||||
return accounts;
|
return accounts;
|
||||||
};
|
};
|
||||||
|
|
||||||
Promise.all([
|
Promise.all([queryLendingAccounts()]).then((all) => {
|
||||||
queryLendingAccounts(),
|
|
||||||
]).then((all) => {
|
|
||||||
setLendingAccounts(all.flat());
|
setLendingAccounts(all.flat());
|
||||||
});
|
});
|
||||||
}, [connection]);
|
}, [connection, processAccount]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const subID = connection.onProgramAccountChange(
|
const subID = connection.onProgramAccountChange(
|
||||||
|
@ -100,7 +126,7 @@ export const useLending = () => {
|
||||||
return () => {
|
return () => {
|
||||||
connection.removeProgramAccountChangeListener(subID);
|
connection.removeProgramAccountChangeListener(subID);
|
||||||
};
|
};
|
||||||
}, [connection, lendingAccounts]);
|
}, [connection, lendingAccounts, processAccount]);
|
||||||
|
|
||||||
return { accounts: lendingAccounts };
|
return { accounts: lendingAccounts };
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
import React, { useCallback, useContext, useEffect, useState } from "react";
|
import React, { useCallback, useContext, useEffect, useState } from "react";
|
||||||
import { MINT_TO_MARKET } from "./../models/marketOverrides";
|
import { MINT_TO_MARKET } from "./../models/marketOverrides";
|
||||||
import {
|
import { STABLE_COINS } from "./../utils/utils";
|
||||||
STABLE_COINS,
|
|
||||||
} from "./../utils/utils";
|
|
||||||
import { useConnectionConfig } from "./connection";
|
import { useConnectionConfig } from "./connection";
|
||||||
import {
|
import { cache, getMultipleAccounts } from "./accounts";
|
||||||
cache,
|
|
||||||
getMultipleAccounts,
|
|
||||||
} from "./accounts";
|
|
||||||
import { Market, MARKETS, Orderbook, TOKEN_MINTS } from "@project-serum/serum";
|
import { Market, MARKETS, Orderbook, TOKEN_MINTS } from "@project-serum/serum";
|
||||||
import { AccountInfo, Connection, PublicKey } from "@solana/web3.js";
|
import { AccountInfo, Connection, PublicKey } from "@solana/web3.js";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
@ -39,14 +34,10 @@ export function MarketProvider({ children = null as any }) {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// TODO: identify which markets to query ...
|
// TODO: identify which markets to query ...
|
||||||
const mints = useMemo(() => [
|
const mints = useMemo(() => [] as PublicKey[], []);
|
||||||
|
|
||||||
] as PublicKey[], []);
|
|
||||||
|
|
||||||
const marketByMint = useMemo(() => {
|
const marketByMint = useMemo(() => {
|
||||||
return [
|
return [...new Set(mints).values()].reduce((acc, key) => {
|
||||||
...new Set(mints).values(),
|
|
||||||
].reduce((acc, key) => {
|
|
||||||
const mintAddress = key.toBase58();
|
const mintAddress = key.toBase58();
|
||||||
|
|
||||||
const SERUM_TOKEN = TOKEN_MINTS.find(
|
const SERUM_TOKEN = TOKEN_MINTS.find(
|
||||||
|
@ -240,8 +231,6 @@ export const useMidPriceInUSD = (mint: string) => {
|
||||||
return { price, isBase: price === 1.0 };
|
return { price, isBase: price === 1.0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const getMidPrice = (marketAddress?: string, mintAddress?: string) => {
|
const getMidPrice = (marketAddress?: string, mintAddress?: string) => {
|
||||||
const SERUM_TOKEN = TOKEN_MINTS.find(
|
const SERUM_TOKEN = TOKEN_MINTS.find(
|
||||||
(a) => a.address.toBase58() === mintAddress
|
(a) => a.address.toBase58() === mintAddress
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export * from './useUserAccounts';
|
export * from "./useUserAccounts";
|
||||||
export * from './useAccountByMint';
|
export * from "./useAccountByMint";
|
||||||
export * from './useLendingReserves';
|
export * from "./useLendingReserves";
|
||||||
export * from './useTokenName';
|
export * from "./useTokenName";
|
||||||
export * from './useUserBalance';
|
export * from "./useUserBalance";
|
||||||
export * from './useCollateralBalance';
|
export * from "./useCollateralBalance";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useUserAccounts } from './useUserAccounts';
|
import { useUserAccounts } from "./useUserAccounts";
|
||||||
|
|
||||||
export const useAccountByMint = (mint: string) => {
|
export const useAccountByMint = (mint: string) => {
|
||||||
const { userAccounts } = useUserAccounts();
|
const { userAccounts } = useUserAccounts();
|
||||||
|
|
|
@ -14,6 +14,6 @@ export function useCollateralBalance(reserve?: LendingReserve) {
|
||||||
return {
|
return {
|
||||||
balance: fromLamports(collateralRatioLamports, mint),
|
balance: fromLamports(collateralRatioLamports, mint),
|
||||||
balanceLamports: collateralRatioLamports,
|
balanceLamports: collateralRatioLamports,
|
||||||
accounts
|
accounts,
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,14 +1,19 @@
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { LendingReserve, LendingReserveParser } from "../models/lending";
|
import { LendingReserve, LendingReserveParser } from "../models/lending";
|
||||||
import { cache, ParsedAccount } from './../contexts/accounts';
|
import { cache, ParsedAccount } from "./../contexts/accounts";
|
||||||
|
|
||||||
const getLendingReserves = () => {
|
const getLendingReserves = () => {
|
||||||
return cache.byParser(LendingReserveParser).map(id => cache.get(id)).filter(acc => acc !== undefined) as any[];
|
return cache
|
||||||
|
.byParser(LendingReserveParser)
|
||||||
|
.map((id) => cache.get(id))
|
||||||
|
.filter((acc) => acc !== undefined) as any[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useLendingReserves() {
|
export function useLendingReserves() {
|
||||||
const [reserveAccounts, setReserveAccounts] = useState<ParsedAccount<LendingReserve>[]>([]);
|
const [reserveAccounts, setReserveAccounts] = useState<
|
||||||
|
ParsedAccount<LendingReserve>[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setReserveAccounts(getLendingReserves());
|
setReserveAccounts(getLendingReserves());
|
||||||
|
@ -22,7 +27,7 @@ export function useLendingReserves() {
|
||||||
return () => {
|
return () => {
|
||||||
dispose();
|
dispose();
|
||||||
};
|
};
|
||||||
}, [setReserveAccounts])
|
}, [setReserveAccounts]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
reserveAccounts,
|
reserveAccounts,
|
||||||
|
@ -30,8 +35,10 @@ export function useLendingReserves() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useLendingReserve(address: string | PublicKey) {
|
export function useLendingReserve(address: string | PublicKey) {
|
||||||
const id = typeof address === 'string' ? address : address?.toBase58();
|
const id = typeof address === "string" ? address : address?.toBase58();
|
||||||
const [reserveAccount, setReserveAccount] = useState<ParsedAccount<LendingReserve>>();
|
const [reserveAccount, setReserveAccount] = useState<
|
||||||
|
ParsedAccount<LendingReserve>
|
||||||
|
>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setReserveAccount(cache.get(id));
|
setReserveAccount(cache.get(id));
|
||||||
|
@ -45,7 +52,7 @@ export function useLendingReserve(address: string | PublicKey) {
|
||||||
return () => {
|
return () => {
|
||||||
dispose();
|
dispose();
|
||||||
};
|
};
|
||||||
}, [setReserveAccount])
|
}, [id, setReserveAccount]);
|
||||||
|
|
||||||
return reserveAccount;
|
return reserveAccount;
|
||||||
}
|
}
|
|
@ -4,6 +4,7 @@ import { getTokenName } from "../utils/utils";
|
||||||
|
|
||||||
export function useTokenName(mintAddress?: string | PublicKey) {
|
export function useTokenName(mintAddress?: string | PublicKey) {
|
||||||
const { tokenMap } = useConnectionConfig();
|
const { tokenMap } = useConnectionConfig();
|
||||||
const address = typeof mintAddress === 'string' ? mintAddress : mintAddress?.toBase58();
|
const address =
|
||||||
|
typeof mintAddress === "string" ? mintAddress : mintAddress?.toBase58();
|
||||||
return getTokenName(tokenMap, address);
|
return getTokenName(tokenMap, address);
|
||||||
}
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
import { TokenAccount } from "../models";
|
import { TokenAccount } from "../models";
|
||||||
import { useAccountsContext } from './../contexts/accounts';
|
import { useAccountsContext } from "./../contexts/accounts";
|
||||||
|
|
||||||
export function useUserAccounts() {
|
export function useUserAccounts() {
|
||||||
const context = useAccountsContext();
|
const context = useAccountsContext();
|
||||||
return {
|
return {
|
||||||
userAccounts: context.userAccounts as TokenAccount[],
|
userAccounts: context.userAccounts as TokenAccount[],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,16 @@ export function useUserBalance(mint?: PublicKey) {
|
||||||
const mintInfo = useMint(mint);
|
const mintInfo = useMint(mint);
|
||||||
const accounts = useMemo(() => {
|
const accounts = useMemo(() => {
|
||||||
return userAccounts
|
return userAccounts
|
||||||
.filter(acc => mint?.equals(acc.info.mint))
|
.filter((acc) => mint?.equals(acc.info.mint))
|
||||||
.sort((a, b) => b.info.amount.sub(a.info.amount).toNumber());
|
.sort((a, b) => b.info.amount.sub(a.info.amount).toNumber());
|
||||||
}, [userAccounts, mint]);
|
}, [userAccounts, mint]);
|
||||||
|
|
||||||
const balanceLamports = useMemo(() => {
|
const balanceLamports = useMemo(() => {
|
||||||
return accounts
|
return accounts.reduce(
|
||||||
.reduce((res, item) => res += item.info.amount.toNumber(), 0);
|
(res, item) => (res += item.info.amount.toNumber()),
|
||||||
},[accounts]);
|
0
|
||||||
|
);
|
||||||
|
}, [accounts]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
balance: fromLamports(balanceLamports, mintInfo),
|
balance: fromLamports(balanceLamports, mintInfo),
|
||||||
|
|
|
@ -20,12 +20,18 @@ export const OrderBookParser = (id: PublicKey, acc: AccountInfo<Buffer>) => {
|
||||||
return details;
|
return details;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_DEX_ID = new PublicKey('EUqojwWA2rd19FZrzeBncJsm38Jm1hEhE3zsmX3bRc2o');
|
const DEFAULT_DEX_ID = new PublicKey(
|
||||||
|
"EUqojwWA2rd19FZrzeBncJsm38Jm1hEhE3zsmX3bRc2o"
|
||||||
|
);
|
||||||
|
|
||||||
export const DexMarketParser = (pubkey: PublicKey, acc: AccountInfo<Buffer>) => {
|
export const DexMarketParser = (
|
||||||
const market = MARKETS.find(m => m.address.equals(pubkey));
|
pubkey: PublicKey,
|
||||||
const decoded = Market.getLayout(market?.programId || DEFAULT_DEX_ID)
|
acc: AccountInfo<Buffer>
|
||||||
.decode(acc.data);
|
) => {
|
||||||
|
const market = MARKETS.find((m) => m.address.equals(pubkey));
|
||||||
|
const decoded = Market.getLayout(market?.programId || DEFAULT_DEX_ID).decode(
|
||||||
|
acc.data
|
||||||
|
);
|
||||||
|
|
||||||
const details = {
|
const details = {
|
||||||
pubkey,
|
pubkey,
|
||||||
|
@ -41,4 +47,4 @@ export const DexMarketParser = (pubkey: PublicKey, acc: AccountInfo<Buffer>) =>
|
||||||
cache.registerParser(details.info.asks, OrderBookParser);
|
cache.registerParser(details.info.asks, OrderBookParser);
|
||||||
|
|
||||||
return details;
|
return details;
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export * from "./account";
|
export * from "./account";
|
||||||
export * from './lending';
|
export * from "./lending";
|
||||||
|
|
|
@ -8,7 +8,7 @@ import BN from "bn.js";
|
||||||
import * as BufferLayout from "buffer-layout";
|
import * as BufferLayout from "buffer-layout";
|
||||||
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../../constants/ids";
|
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../../constants/ids";
|
||||||
import * as Layout from "./../../utils/layout";
|
import * as Layout from "./../../utils/layout";
|
||||||
import { LendingInstruction } from './lending';
|
import { LendingInstruction } from "./lending";
|
||||||
|
|
||||||
/// Borrow tokens from a reserve by depositing collateral tokens. The number of borrowed tokens
|
/// Borrow tokens from a reserve by depositing collateral tokens. The number of borrowed tokens
|
||||||
/// is calculated by market price. The debt obligation is tokenized.
|
/// is calculated by market price. The debt obligation is tokenized.
|
||||||
|
@ -49,7 +49,7 @@ export const borrowInstruction = (
|
||||||
dexMarket: PublicKey,
|
dexMarket: PublicKey,
|
||||||
dexOrderBookSide: PublicKey,
|
dexOrderBookSide: PublicKey,
|
||||||
|
|
||||||
memory: PublicKey,
|
memory: PublicKey
|
||||||
): TransactionInstruction => {
|
): TransactionInstruction => {
|
||||||
const dataLayout = BufferLayout.struct([
|
const dataLayout = BufferLayout.struct([
|
||||||
BufferLayout.u8("instruction"),
|
BufferLayout.u8("instruction"),
|
||||||
|
@ -69,9 +69,17 @@ export const borrowInstruction = (
|
||||||
{ pubkey: from, isSigner: false, isWritable: true },
|
{ pubkey: from, isSigner: false, isWritable: true },
|
||||||
{ pubkey: to, isSigner: false, isWritable: true },
|
{ pubkey: to, isSigner: false, isWritable: true },
|
||||||
{ pubkey: depositReserve, isSigner: false, isWritable: true },
|
{ pubkey: depositReserve, isSigner: false, isWritable: true },
|
||||||
{ pubkey: depositReserveCollateralSupply, isSigner: false, isWritable: true },
|
{
|
||||||
|
pubkey: depositReserveCollateralSupply,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: true,
|
||||||
|
},
|
||||||
{ pubkey: borrowReserve, isSigner: false, isWritable: true },
|
{ pubkey: borrowReserve, isSigner: false, isWritable: true },
|
||||||
{ pubkey: borrowReserveLiquiditySupply, isSigner: false, isWritable: false },
|
{
|
||||||
|
pubkey: borrowReserveLiquiditySupply,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
{ pubkey: obligation, isSigner: false, isWritable: true },
|
{ pubkey: obligation, isSigner: false, isWritable: true },
|
||||||
{ pubkey: obligationMint, isSigner: false, isWritable: true },
|
{ pubkey: obligationMint, isSigner: false, isWritable: true },
|
||||||
{ pubkey: obligationTokenOutput, isSigner: false, isWritable: true },
|
{ pubkey: obligationTokenOutput, isSigner: false, isWritable: true },
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export * from './market';
|
export * from "./market";
|
||||||
export * from './reserve';
|
export * from "./reserve";
|
||||||
export * from './obligation';
|
export * from "./obligation";
|
||||||
export * from './lending';
|
export * from "./lending";
|
||||||
export * from './borrow';
|
export * from "./borrow";
|
||||||
|
|
|
@ -4,5 +4,5 @@ export enum LendingInstruction {
|
||||||
DepositReserveLiquidity = 2,
|
DepositReserveLiquidity = 2,
|
||||||
WithdrawReserveLiquidity = 3,
|
WithdrawReserveLiquidity = 3,
|
||||||
BorrowReserveLiquidity = 4,
|
BorrowReserveLiquidity = 4,
|
||||||
RepayReserveLiquidity = 5
|
RepayReserveLiquidity = 5,
|
||||||
}
|
}
|
|
@ -1,15 +1,9 @@
|
||||||
import {
|
import { AccountInfo, PublicKey } from "@solana/web3.js";
|
||||||
AccountInfo,
|
|
||||||
PublicKey,
|
|
||||||
} from "@solana/web3.js";
|
|
||||||
import * as BufferLayout from "buffer-layout";
|
import * as BufferLayout from "buffer-layout";
|
||||||
import * as Layout from "./../../utils/layout";
|
import * as Layout from "./../../utils/layout";
|
||||||
|
|
||||||
export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
||||||
[
|
[BufferLayout.u8("isInitialized"), Layout.publicKey("quoteMint")]
|
||||||
BufferLayout.u8("isInitialized"),
|
|
||||||
Layout.publicKey("quoteMint"),
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export interface LendingMarket {
|
export interface LendingMarket {
|
||||||
|
@ -19,9 +13,12 @@ export interface LendingMarket {
|
||||||
|
|
||||||
export const isLendingMarket = (info: AccountInfo<Buffer>) => {
|
export const isLendingMarket = (info: AccountInfo<Buffer>) => {
|
||||||
return info.data.length === LendingMarketLayout.span;
|
return info.data.length === LendingMarketLayout.span;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const LendingMarketParser = (pubKey: PublicKey, info: AccountInfo<Buffer>) => {
|
export const LendingMarketParser = (
|
||||||
|
pubKey: PublicKey,
|
||||||
|
info: AccountInfo<Buffer>
|
||||||
|
) => {
|
||||||
const buffer = Buffer.from(info.data);
|
const buffer = Buffer.from(info.data);
|
||||||
const data = LendingMarketLayout.decode(buffer);
|
const data = LendingMarketLayout.decode(buffer);
|
||||||
|
|
||||||
|
@ -36,6 +33,5 @@ export const LendingMarketParser = (pubKey: PublicKey, info: AccountInfo<Buffer>
|
||||||
return details;
|
return details;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// create instructions for init
|
// create instructions for init
|
|
@ -1,6 +1,4 @@
|
||||||
import {
|
import { PublicKey } from "@solana/web3.js";
|
||||||
PublicKey,
|
|
||||||
} from "@solana/web3.js";
|
|
||||||
import BN from "bn.js";
|
import BN from "bn.js";
|
||||||
import * as BufferLayout from "buffer-layout";
|
import * as BufferLayout from "buffer-layout";
|
||||||
import * as Layout from "./../../utils/layout";
|
import * as Layout from "./../../utils/layout";
|
||||||
|
|
|
@ -9,7 +9,7 @@ import BN from "bn.js";
|
||||||
import * as BufferLayout from "buffer-layout";
|
import * as BufferLayout from "buffer-layout";
|
||||||
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../../constants/ids";
|
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../../constants/ids";
|
||||||
import * as Layout from "./../../utils/layout";
|
import * as Layout from "./../../utils/layout";
|
||||||
import { LendingInstruction } from './lending';
|
import { LendingInstruction } from "./lending";
|
||||||
|
|
||||||
export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
||||||
[
|
[
|
||||||
|
@ -21,10 +21,11 @@ export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.
|
||||||
Layout.publicKey("collateralMint"),
|
Layout.publicKey("collateralMint"),
|
||||||
Layout.publicKey("collateralSupply"),
|
Layout.publicKey("collateralSupply"),
|
||||||
// TODO: replace u32 option with generic quivalent
|
// TODO: replace u32 option with generic quivalent
|
||||||
BufferLayout.u32('dexMarketOption'),
|
BufferLayout.u32("dexMarketOption"),
|
||||||
Layout.publicKey("dexMarket"),
|
Layout.publicKey("dexMarket"),
|
||||||
|
|
||||||
BufferLayout.struct([
|
BufferLayout.struct(
|
||||||
|
[
|
||||||
/// Max utilization rate as a percent
|
/// Max utilization rate as a percent
|
||||||
BufferLayout.u8("maxUtilizationRate"),
|
BufferLayout.u8("maxUtilizationRate"),
|
||||||
/// The ratio of the loan to the value of the collateral as a percent
|
/// The ratio of the loan to the value of the collateral as a percent
|
||||||
|
@ -33,7 +34,9 @@ export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.
|
||||||
BufferLayout.u8("liquidationBonus"),
|
BufferLayout.u8("liquidationBonus"),
|
||||||
/// The percent at which an obligation is considered unhealthy
|
/// The percent at which an obligation is considered unhealthy
|
||||||
BufferLayout.u8("liquidationThreshold"),
|
BufferLayout.u8("liquidationThreshold"),
|
||||||
], "config"),
|
],
|
||||||
|
"config"
|
||||||
|
),
|
||||||
|
|
||||||
Layout.uint128("cumulativeBorrowRate"),
|
Layout.uint128("cumulativeBorrowRate"),
|
||||||
Layout.uint128("totalBorrows"),
|
Layout.uint128("totalBorrows"),
|
||||||
|
@ -47,7 +50,7 @@ export const isLendingReserve = (info: AccountInfo<Buffer>) => {
|
||||||
console.log(LendingReserveLayout.span);
|
console.log(LendingReserveLayout.span);
|
||||||
console.log(info.data.length);
|
console.log(info.data.length);
|
||||||
return info.data.length === LendingReserveLayout.span;
|
return info.data.length === LendingReserveLayout.span;
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface LendingReserve {
|
export interface LendingReserve {
|
||||||
lastUpdateSlot: BN;
|
lastUpdateSlot: BN;
|
||||||
|
@ -63,11 +66,11 @@ export interface LendingReserve {
|
||||||
dexMarketPrice: BN; // what is precision on the price?
|
dexMarketPrice: BN; // what is precision on the price?
|
||||||
|
|
||||||
config: {
|
config: {
|
||||||
maxUtilizationRate: number,
|
maxUtilizationRate: number;
|
||||||
loanToValueRatio: number,
|
loanToValueRatio: number;
|
||||||
liquidationBonus: number,
|
liquidationBonus: number;
|
||||||
liquidationThreshold: number,
|
liquidationThreshold: number;
|
||||||
}
|
};
|
||||||
// collateralFactor: number;
|
// collateralFactor: number;
|
||||||
|
|
||||||
cumulativeBorrowRate: BN;
|
cumulativeBorrowRate: BN;
|
||||||
|
@ -80,7 +83,10 @@ export interface LendingReserve {
|
||||||
// Layout.uint128("total_borrows"),
|
// Layout.uint128("total_borrows"),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LendingReserveParser = (pubKey: PublicKey, info: AccountInfo<Buffer>) => {
|
export const LendingReserveParser = (
|
||||||
|
pubKey: PublicKey,
|
||||||
|
info: AccountInfo<Buffer>
|
||||||
|
) => {
|
||||||
const buffer = Buffer.from(info.data);
|
const buffer = Buffer.from(info.data);
|
||||||
const data = LendingReserveLayout.decode(buffer);
|
const data = LendingReserveLayout.decode(buffer);
|
||||||
|
|
||||||
|
@ -110,12 +116,12 @@ export const initReserveInstruction = (
|
||||||
lendingMarket: PublicKey,
|
lendingMarket: PublicKey,
|
||||||
lendingMarketAuthority: PublicKey,
|
lendingMarketAuthority: PublicKey,
|
||||||
|
|
||||||
dexMarket: PublicKey, // TODO: optional
|
dexMarket: PublicKey // TODO: optional
|
||||||
): TransactionInstruction => {
|
): TransactionInstruction => {
|
||||||
const dataLayout = BufferLayout.struct([
|
const dataLayout = BufferLayout.struct([
|
||||||
BufferLayout.u8("instruction"),
|
BufferLayout.u8("instruction"),
|
||||||
Layout.uint64("liquidityAmount"),
|
Layout.uint64("liquidityAmount"),
|
||||||
BufferLayout.u8("maxUtilizationRate")
|
BufferLayout.u8("maxUtilizationRate"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const data = Buffer.alloc(dataLayout.span);
|
const data = Buffer.alloc(dataLayout.span);
|
||||||
|
@ -172,7 +178,7 @@ export const depositInstruction = (
|
||||||
reserveAuthority: PublicKey,
|
reserveAuthority: PublicKey,
|
||||||
reserveAccount: PublicKey,
|
reserveAccount: PublicKey,
|
||||||
reserveSupply: PublicKey,
|
reserveSupply: PublicKey,
|
||||||
collateralMint: PublicKey,
|
collateralMint: PublicKey
|
||||||
): TransactionInstruction => {
|
): TransactionInstruction => {
|
||||||
const dataLayout = BufferLayout.struct([
|
const dataLayout = BufferLayout.struct([
|
||||||
BufferLayout.u8("instruction"),
|
BufferLayout.u8("instruction"),
|
||||||
|
@ -212,7 +218,7 @@ export const withdrawInstruction = (
|
||||||
reserveAccount: PublicKey,
|
reserveAccount: PublicKey,
|
||||||
collateralMint: PublicKey,
|
collateralMint: PublicKey,
|
||||||
reserveSupply: PublicKey,
|
reserveSupply: PublicKey,
|
||||||
authority: PublicKey,
|
authority: PublicKey
|
||||||
): TransactionInstruction => {
|
): TransactionInstruction => {
|
||||||
const dataLayout = BufferLayout.struct([
|
const dataLayout = BufferLayout.struct([
|
||||||
BufferLayout.u8("instruction"),
|
BufferLayout.u8("instruction"),
|
||||||
|
@ -244,4 +250,3 @@ export const withdrawInstruction = (
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
BorrowReserveView,
|
BorrowReserveView,
|
||||||
WithdrawView,
|
WithdrawView,
|
||||||
FaucetView,
|
FaucetView,
|
||||||
} from './views';
|
} from "./views";
|
||||||
|
|
||||||
export function Routes() {
|
export function Routes() {
|
||||||
return (
|
return (
|
||||||
|
@ -31,13 +31,27 @@ export function Routes() {
|
||||||
<AppLayout>
|
<AppLayout>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/" component={() => <HomeView />} />
|
<Route exact path="/" component={() => <HomeView />} />
|
||||||
<Route exact path="/dashboard" children={<DashboardView />} />
|
<Route
|
||||||
|
exact
|
||||||
|
path="/dashboard"
|
||||||
|
children={<DashboardView />}
|
||||||
|
/>
|
||||||
<Route path="/reserve/:id" children={<ReserveView />} />
|
<Route path="/reserve/:id" children={<ReserveView />} />
|
||||||
<Route exact path="/deposit" component={() => <DepositView />} />
|
<Route
|
||||||
<Route path="/deposit/:id" children={<DepositReserveView />} />
|
exact
|
||||||
|
path="/deposit"
|
||||||
|
component={() => <DepositView />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/deposit/:id"
|
||||||
|
children={<DepositReserveView />}
|
||||||
|
/>
|
||||||
<Route path="/withdraw/:id" children={<WithdrawView />} />
|
<Route path="/withdraw/:id" children={<WithdrawView />} />
|
||||||
<Route exact path="/borrow" children={<BorrowView />} />
|
<Route exact path="/borrow" children={<BorrowView />} />
|
||||||
<Route path="/borrow/:id" children={<BorrowReserveView />} />
|
<Route
|
||||||
|
path="/borrow/:id"
|
||||||
|
children={<BorrowReserveView />}
|
||||||
|
/>
|
||||||
<Route exact path="/faucet" children={<FaucetView />} />
|
<Route exact path="/faucet" children={<FaucetView />} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</AppLayout>
|
</AppLayout>
|
||||||
|
|
|
@ -44,7 +44,7 @@ export class EventEmitter {
|
||||||
onCache(callback: (args: CacheUpdateEvent) => void) {
|
onCache(callback: (args: CacheUpdateEvent) => void) {
|
||||||
this.emitter.on(CacheUpdateEvent.type, callback);
|
this.emitter.on(CacheUpdateEvent.type, callback);
|
||||||
|
|
||||||
return () => this.emitter.removeListener(CacheUpdateEvent .type, callback);
|
return () => this.emitter.removeListener(CacheUpdateEvent.type, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
raiseAccountUpdated(id: string) {
|
raiseAccountUpdated(id: string) {
|
||||||
|
|
|
@ -32,15 +32,14 @@ export const uint64 = (property = "uint64"): unknown => {
|
||||||
const _decode = layout.decode.bind(layout);
|
const _decode = layout.decode.bind(layout);
|
||||||
const _encode = layout.encode.bind(layout);
|
const _encode = layout.encode.bind(layout);
|
||||||
|
|
||||||
|
|
||||||
layout.decode = (buffer: Buffer, offset: number) => {
|
layout.decode = (buffer: Buffer, offset: number) => {
|
||||||
const data = _decode(buffer, offset);
|
const data = _decode(buffer, offset);
|
||||||
return new BN(
|
return new BN(
|
||||||
[...data]
|
[...data]
|
||||||
.reverse()
|
.reverse()
|
||||||
.map(i => `00${i.toString(16)}`.slice(-2))
|
.map((i) => `00${i.toString(16)}`.slice(-2))
|
||||||
.join(''),
|
.join(""),
|
||||||
16,
|
16
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,15 +64,14 @@ export const uint128 = (property = "uint128"): unknown => {
|
||||||
const _decode = layout.decode.bind(layout);
|
const _decode = layout.decode.bind(layout);
|
||||||
const _encode = layout.encode.bind(layout);
|
const _encode = layout.encode.bind(layout);
|
||||||
|
|
||||||
|
|
||||||
layout.decode = (buffer: Buffer, offset: number) => {
|
layout.decode = (buffer: Buffer, offset: number) => {
|
||||||
const data = _decode(buffer, offset);
|
const data = _decode(buffer, offset);
|
||||||
return new BN(
|
return new BN(
|
||||||
[...data]
|
[...data]
|
||||||
.reverse()
|
.reverse()
|
||||||
.map(i => `00${i.toString(16)}`.slice(-2))
|
.map((i) => `00${i.toString(16)}`.slice(-2))
|
||||||
.join(''),
|
.join(""),
|
||||||
16,
|
16
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,7 +87,6 @@ export const uint128 = (property = "uint128"): unknown => {
|
||||||
return _encode(b, buffer, offset);
|
return _encode(b, buffer, offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return layout;
|
return layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ export function getTokenName(
|
||||||
shorten = true
|
shorten = true
|
||||||
): string {
|
): string {
|
||||||
if (!mintAddress) {
|
if (!mintAddress) {
|
||||||
return 'N/A';
|
return "N/A";
|
||||||
}
|
}
|
||||||
|
|
||||||
const knownSymbol = map.get(mintAddress)?.tokenSymbol;
|
const knownSymbol = map.get(mintAddress)?.tokenSymbol;
|
||||||
|
@ -66,9 +66,10 @@ export function getTokenName(
|
||||||
|
|
||||||
export function getTokenIcon(
|
export function getTokenIcon(
|
||||||
map: KnownTokenMap,
|
map: KnownTokenMap,
|
||||||
mintAddress?: string | PublicKey,
|
mintAddress?: string | PublicKey
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
const address = typeof mintAddress === 'string' ? mintAddress : mintAddress?.toBase58();
|
const address =
|
||||||
|
typeof mintAddress === "string" ? mintAddress : mintAddress?.toBase58();
|
||||||
if (!address) {
|
if (!address) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +102,7 @@ export function toLamports(
|
||||||
typeof account === "number" ? account : account.info.amount?.toNumber();
|
typeof account === "number" ? account : account.info.amount?.toNumber();
|
||||||
|
|
||||||
const precision = Math.pow(10, mint?.decimals || 0);
|
const precision = Math.pow(10, mint?.decimals || 0);
|
||||||
return (amount * precision);
|
return amount * precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fromLamports(
|
export function fromLamports(
|
||||||
|
@ -171,12 +172,12 @@ const numberFormater = new Intl.NumberFormat("en-US", {
|
||||||
export const formatNumber = {
|
export const formatNumber = {
|
||||||
format: (val?: number) => {
|
format: (val?: number) => {
|
||||||
if (!val) {
|
if (!val) {
|
||||||
return '--';
|
return "--";
|
||||||
}
|
}
|
||||||
|
|
||||||
return numberFormater.format(val);
|
return numberFormater.format(val);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export const formatPct = new Intl.NumberFormat("en-US", {
|
export const formatPct = new Intl.NumberFormat("en-US", {
|
||||||
style: "percent",
|
style: "percent",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useLendingReserves } from '../../hooks';
|
import { useLendingReserves } from "../../hooks";
|
||||||
import { BorrowItem } from './item';
|
import { BorrowItem } from "./item";
|
||||||
import './itemStyle.less';
|
import "./itemStyle.less";
|
||||||
|
|
||||||
export const BorrowView = () => {
|
export const BorrowView = () => {
|
||||||
const { reserveAccounts } = useLendingReserves();
|
const { reserveAccounts } = useLendingReserves();
|
||||||
|
@ -13,7 +13,9 @@ export const BorrowView = () => {
|
||||||
<div>APY</div>
|
<div>APY</div>
|
||||||
<div>Action</div>
|
<div>Action</div>
|
||||||
</div>
|
</div>
|
||||||
{reserveAccounts.map(account => <BorrowItem reserve={account.info} address={account.pubkey} />)}
|
{reserveAccounts.map((account) => (
|
||||||
|
<BorrowItem reserve={account.info} address={account.pubkey} />
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useCollateralBalance, useTokenName } from '../../hooks';
|
import { useCollateralBalance, useTokenName } from "../../hooks";
|
||||||
import { LendingReserve } from "../../models/lending";
|
import { LendingReserve } from "../../models/lending";
|
||||||
import { TokenIcon } from "../../components/TokenIcon";
|
import { TokenIcon } from "../../components/TokenIcon";
|
||||||
import { formatNumber } from "../../utils/utils";
|
import { formatNumber } from "../../utils/utils";
|
||||||
|
@ -7,17 +7,26 @@ import { Button, Card } from "antd";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
|
|
||||||
export const BorrowItem = (props: { reserve: LendingReserve, address: PublicKey }) => {
|
export const BorrowItem = (props: {
|
||||||
|
reserve: LendingReserve;
|
||||||
|
address: PublicKey;
|
||||||
|
}) => {
|
||||||
const name = useTokenName(props.reserve.liquidityMint);
|
const name = useTokenName(props.reserve.liquidityMint);
|
||||||
|
|
||||||
// TODO: calculate avilable amount... based on total owned collateral across all the reserves
|
// TODO: calculate avilable amount... based on total owned collateral across all the reserves
|
||||||
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
|
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
|
||||||
|
|
||||||
return <Link to={`/borrow/${props.address.toBase58()}`}>
|
return (
|
||||||
|
<Link to={`/borrow/${props.address.toBase58()}`}>
|
||||||
<Card>
|
<Card>
|
||||||
<div className="borrow-item">
|
<div className="borrow-item">
|
||||||
<span style={{ display: 'flex' }}><TokenIcon mintAddress={props.reserve.liquidityMint} />{name}</span>
|
<span style={{ display: "flex" }}>
|
||||||
<div>{formatNumber.format(collateralBalance)} {name}</div>
|
<TokenIcon mintAddress={props.reserve.liquidityMint} />
|
||||||
|
{name}
|
||||||
|
</span>
|
||||||
|
<div>
|
||||||
|
{formatNumber.format(collateralBalance)} {name}
|
||||||
|
</div>
|
||||||
<div>--</div>
|
<div>--</div>
|
||||||
<div>
|
<div>
|
||||||
<Button>
|
<Button>
|
||||||
|
@ -26,5 +35,6 @@ export const BorrowItem = (props: { reserve: LendingReserve, address: PublicKey
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</Link>;
|
</Link>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import React, { } from "react";
|
import React from "react";
|
||||||
import { useLendingReserve } from '../../hooks';
|
import { useLendingReserve } from "../../hooks";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import './style.less';
|
import "./style.less";
|
||||||
|
|
||||||
import { BorrowInput } from '../../components/BorrowInput';
|
import { BorrowInput } from "../../components/BorrowInput";
|
||||||
import { SideReserveOverview, SideReserveOverviewMode } from '../../components/SideReserveOverview';
|
import {
|
||||||
|
SideReserveOverview,
|
||||||
|
SideReserveOverviewMode,
|
||||||
|
} from "../../components/SideReserveOverview";
|
||||||
|
|
||||||
export const BorrowReserveView = () => {
|
export const BorrowReserveView = () => {
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
|
@ -15,17 +18,21 @@ export const BorrowReserveView = () => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="borrow-reserve">
|
return (
|
||||||
|
<div className="borrow-reserve">
|
||||||
<div className="borrow-reserve-container">
|
<div className="borrow-reserve-container">
|
||||||
<BorrowInput
|
<BorrowInput
|
||||||
className="borrow-reserve-item borrow-reserve-item-left"
|
className="borrow-reserve-item borrow-reserve-item-left"
|
||||||
reserve={reserve}
|
reserve={reserve}
|
||||||
address={lendingReserve.pubkey} />
|
address={lendingReserve.pubkey}
|
||||||
|
/>
|
||||||
<SideReserveOverview
|
<SideReserveOverview
|
||||||
className="borrow-reserve-item borrow-reserve-item-right"
|
className="borrow-reserve-item borrow-reserve-item-right"
|
||||||
reserve={reserve}
|
reserve={reserve}
|
||||||
address={lendingReserve.pubkey}
|
address={lendingReserve.pubkey}
|
||||||
mode={SideReserveOverviewMode.Borrow} />
|
mode={SideReserveOverviewMode.Borrow}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export const DashboardView = () => {
|
export const DashboardView = () => {
|
||||||
|
return (
|
||||||
return <div className="flexColumn">
|
<div className="flexColumn">
|
||||||
DASHBOARD:
|
DASHBOARD: TODO: 1. Add deposits 2. Add obligations
|
||||||
TODO:
|
</div>
|
||||||
1. Add deposits
|
);
|
||||||
2. Add obligations
|
};
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export * from './view';
|
export * from "./view";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useLendingReserves } from '../../../hooks';
|
import { useLendingReserves } from "../../../hooks";
|
||||||
import { ReserveItem } from './item';
|
import { ReserveItem } from "./item";
|
||||||
import './itemStyle.less';
|
import "./itemStyle.less";
|
||||||
|
|
||||||
export const DepositView = () => {
|
export const DepositView = () => {
|
||||||
const { reserveAccounts } = useLendingReserves();
|
const { reserveAccounts } = useLendingReserves();
|
||||||
|
@ -14,7 +14,9 @@ export const DepositView = () => {
|
||||||
<div>APY</div>
|
<div>APY</div>
|
||||||
<div>Action</div>
|
<div>Action</div>
|
||||||
</div>
|
</div>
|
||||||
{reserveAccounts.map(account => <ReserveItem reserve={account.info} address={account.pubkey} />)}
|
{reserveAccounts.map((account) => (
|
||||||
|
<ReserveItem reserve={account.info} address={account.pubkey} />
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
|
@ -1,5 +1,9 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useCollateralBalance, useTokenName, useUserBalance } from '../../../hooks';
|
import {
|
||||||
|
useCollateralBalance,
|
||||||
|
useTokenName,
|
||||||
|
useUserBalance,
|
||||||
|
} from "../../../hooks";
|
||||||
import { LendingReserve } from "../../../models/lending";
|
import { LendingReserve } from "../../../models/lending";
|
||||||
import { TokenIcon } from "../../../components/TokenIcon";
|
import { TokenIcon } from "../../../components/TokenIcon";
|
||||||
import { formatNumber } from "../../../utils/utils";
|
import { formatNumber } from "../../../utils/utils";
|
||||||
|
@ -7,17 +11,28 @@ import { Button, Card } from "antd";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
|
|
||||||
export const ReserveItem = (props: { reserve: LendingReserve, address: PublicKey }) => {
|
export const ReserveItem = (props: {
|
||||||
|
reserve: LendingReserve;
|
||||||
|
address: PublicKey;
|
||||||
|
}) => {
|
||||||
const name = useTokenName(props.reserve.liquidityMint);
|
const name = useTokenName(props.reserve.liquidityMint);
|
||||||
const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint);
|
const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint);
|
||||||
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
|
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
|
||||||
|
|
||||||
return <Link to={`/deposit/${props.address.toBase58()}`}>
|
return (
|
||||||
|
<Link to={`/deposit/${props.address.toBase58()}`}>
|
||||||
<Card>
|
<Card>
|
||||||
<div className="deposit-item">
|
<div className="deposit-item">
|
||||||
<span style={{ display: 'flex' }}><TokenIcon mintAddress={props.reserve.liquidityMint} />{name}</span>
|
<span style={{ display: "flex" }}>
|
||||||
<div>{formatNumber.format(tokenBalance)} {name}</div>
|
<TokenIcon mintAddress={props.reserve.liquidityMint} />
|
||||||
<div>{formatNumber.format(collateralBalance)} {name}</div>
|
{name}
|
||||||
|
</span>
|
||||||
|
<div>
|
||||||
|
{formatNumber.format(tokenBalance)} {name}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{formatNumber.format(collateralBalance)} {name}
|
||||||
|
</div>
|
||||||
<div>--</div>
|
<div>--</div>
|
||||||
<div>
|
<div>
|
||||||
<Button>
|
<Button>
|
||||||
|
@ -26,5 +41,6 @@ export const ReserveItem = (props: { reserve: LendingReserve, address: PublicKey
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</Link>;
|
</Link>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import React, { } from "react";
|
import React from "react";
|
||||||
import { useLendingReserve } from '../../hooks';
|
import { useLendingReserve } from "../../hooks";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import './style.less';
|
import "./style.less";
|
||||||
|
|
||||||
import { DepositInput } from '../../components/DepositInput';
|
import { DepositInput } from "../../components/DepositInput";
|
||||||
import { DepositInfoLine } from '../../components/DepositInfoLine';
|
import { DepositInfoLine } from "../../components/DepositInfoLine";
|
||||||
import { SideReserveOverview, SideReserveOverviewMode } from '../../components/SideReserveOverview';
|
import {
|
||||||
|
SideReserveOverview,
|
||||||
|
SideReserveOverviewMode,
|
||||||
|
} from "../../components/SideReserveOverview";
|
||||||
|
|
||||||
export const DepositReserveView = () => {
|
export const DepositReserveView = () => {
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
|
@ -16,21 +19,26 @@ export const DepositReserveView = () => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="deposit-reserve">
|
return (
|
||||||
|
<div className="deposit-reserve">
|
||||||
<DepositInfoLine
|
<DepositInfoLine
|
||||||
className="deposit-reserve-item"
|
className="deposit-reserve-item"
|
||||||
reserve={reserve}
|
reserve={reserve}
|
||||||
address={lendingReserve.pubkey} />
|
address={lendingReserve.pubkey}
|
||||||
|
/>
|
||||||
<div className="deposit-reserve-container">
|
<div className="deposit-reserve-container">
|
||||||
<DepositInput
|
<DepositInput
|
||||||
className="deposit-reserve-item deposit-reserve-item-left"
|
className="deposit-reserve-item deposit-reserve-item-left"
|
||||||
reserve={reserve}
|
reserve={reserve}
|
||||||
address={lendingReserve.pubkey} />
|
address={lendingReserve.pubkey}
|
||||||
|
/>
|
||||||
<SideReserveOverview
|
<SideReserveOverview
|
||||||
className="deposit-reserve-item deposit-reserve-item-right"
|
className="deposit-reserve-item deposit-reserve-item-right"
|
||||||
reserve={reserve}
|
reserve={reserve}
|
||||||
address={lendingReserve.pubkey}
|
address={lendingReserve.pubkey}
|
||||||
mode={SideReserveOverviewMode.Deposit} />
|
mode={SideReserveOverviewMode.Deposit}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -10,27 +10,36 @@ export const FaucetView = () => {
|
||||||
|
|
||||||
const airdrop = useCallback(() => {
|
const airdrop = useCallback(() => {
|
||||||
connection.requestAirdrop(wallet.publicKey, 1 * LAMPORTS_PER_SOL);
|
connection.requestAirdrop(wallet.publicKey, 1 * LAMPORTS_PER_SOL);
|
||||||
}, [wallet, connection])
|
}, [wallet, connection]);
|
||||||
|
|
||||||
const bodyStyle: React.CSSProperties = {
|
const bodyStyle: React.CSSProperties = {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
height: '100%',
|
height: "100%",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flexColumn" style={{ flex: 1 }}>
|
<div className="flexColumn" style={{ flex: 1 }}>
|
||||||
<Card title={'Faucet'} bodyStyle={bodyStyle} style={{ flex: 1 }}>
|
<Card title={"Faucet"} bodyStyle={bodyStyle} style={{ flex: 1 }}>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-around', alignItems: 'center' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="deposit-input-title" style={{ margin: 10 }}>
|
<div className="deposit-input-title" style={{ margin: 10 }}>
|
||||||
This Faucet will help you fund your accounts outside of Solana main network.
|
This Faucet will help you fund your accounts outside of Solana main
|
||||||
|
network.
|
||||||
</div>
|
</div>
|
||||||
<Button type="primary" onClick={airdrop} >Give me SOL</Button>
|
<Button type="primary" onClick={airdrop}>
|
||||||
|
Give me SOL
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useLendingReserves } from '../../hooks';
|
import { useLendingReserves } from "../../hooks";
|
||||||
import { LendingReserveItem } from "./item";
|
import { LendingReserveItem } from "./item";
|
||||||
import './itemStyle.less';
|
import "./itemStyle.less";
|
||||||
|
|
||||||
export const HomeView = () => {
|
export const HomeView = () => {
|
||||||
const { reserveAccounts } = useLendingReserves();
|
const { reserveAccounts } = useLendingReserves();
|
||||||
|
|
||||||
// TODO: add total Liquidity amount ...
|
// TODO: add total Liquidity amount ...
|
||||||
|
|
||||||
return <div className="flexColumn">
|
return (
|
||||||
|
<div className="flexColumn">
|
||||||
<div className="home-item home-header">
|
<div className="home-item home-header">
|
||||||
<div>Asset</div>
|
<div>Asset</div>
|
||||||
<div>Market Size</div>
|
<div>Market Size</div>
|
||||||
|
@ -16,6 +17,9 @@ export const HomeView = () => {
|
||||||
<div>Deposit APY</div>
|
<div>Deposit APY</div>
|
||||||
<div>Borrow APY</div>
|
<div>Borrow APY</div>
|
||||||
</div>
|
</div>
|
||||||
{reserveAccounts.map(account => <LendingReserveItem reserve={account.info} address={account.pubkey} />)}
|
{reserveAccounts.map((account) => (
|
||||||
</div>;
|
<LendingReserveItem reserve={account.info} address={account.pubkey} />
|
||||||
}
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTokenName } from '../../hooks';
|
import { useTokenName } from "../../hooks";
|
||||||
import { LendingReserve } from "../../models/lending";
|
import { LendingReserve } from "../../models/lending";
|
||||||
import { TokenIcon } from "../../components/TokenIcon";
|
import { TokenIcon } from "../../components/TokenIcon";
|
||||||
import { formatNumber, fromLamports } from "../../utils/utils";
|
import { formatNumber, fromLamports } from "../../utils/utils";
|
||||||
|
@ -8,26 +8,40 @@ import { Link } from "react-router-dom";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import { useMint } from "../../contexts/accounts";
|
import { useMint } from "../../contexts/accounts";
|
||||||
|
|
||||||
export const LendingReserveItem = (props: { reserve: LendingReserve, address: PublicKey }) => {
|
export const LendingReserveItem = (props: {
|
||||||
|
reserve: LendingReserve;
|
||||||
|
address: PublicKey;
|
||||||
|
}) => {
|
||||||
const name = useTokenName(props.reserve.liquidityMint);
|
const name = useTokenName(props.reserve.liquidityMint);
|
||||||
|
|
||||||
const liquidityMint = useMint(props.reserve.liquidityMint);
|
const liquidityMint = useMint(props.reserve.liquidityMint);
|
||||||
|
|
||||||
const totalLiquidity = fromLamports(props.reserve.totalLiquidity.toNumber(), liquidityMint);
|
const totalLiquidity = fromLamports(
|
||||||
|
props.reserve.totalLiquidity.toNumber(),
|
||||||
|
liquidityMint
|
||||||
|
);
|
||||||
const totalBorrows = props.reserve.totalBorrows.toString();
|
const totalBorrows = props.reserve.totalBorrows.toString();
|
||||||
|
|
||||||
console.log(liquidityMint);
|
console.log(liquidityMint);
|
||||||
|
|
||||||
return <Link to={`/reserve/${props.address.toBase58()}`}>
|
return (
|
||||||
|
<Link to={`/reserve/${props.address.toBase58()}`}>
|
||||||
<Card>
|
<Card>
|
||||||
<div className="home-item">
|
<div className="home-item">
|
||||||
<span style={{ display: 'flex' }}><TokenIcon mintAddress={props.reserve.liquidityMint} />{name}</span>
|
<span style={{ display: "flex" }}>
|
||||||
<div>{formatNumber.format(totalLiquidity)} {name}</div>
|
<TokenIcon mintAddress={props.reserve.liquidityMint} />
|
||||||
<div>{totalBorrows} {name}</div>
|
{name}
|
||||||
|
</span>
|
||||||
|
<div>
|
||||||
|
{formatNumber.format(totalLiquidity)} {name}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{totalBorrows} {name}
|
||||||
|
</div>
|
||||||
<div>--</div>
|
<div>--</div>
|
||||||
<div>--</div>
|
<div>--</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</Card>
|
</Card>
|
||||||
</Link>;
|
</Link>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
export { HomeView } from './home';
|
export { HomeView } from "./home";
|
||||||
export { BorrowView } from './borrow';
|
export { BorrowView } from "./borrow";
|
||||||
export { BorrowReserveView } from './borrowReserve';
|
export { BorrowReserveView } from "./borrowReserve";
|
||||||
export { DashboardView } from './dashboard';
|
export { DashboardView } from "./dashboard";
|
||||||
export { DepositView } from './deposit';
|
export { DepositView } from "./deposit";
|
||||||
export { DepositReserveView } from './depositReserve';
|
export { DepositReserveView } from "./depositReserve";
|
||||||
export { ReserveView } from './reserve';
|
export { ReserveView } from "./reserve";
|
||||||
export { WithdrawView } from './withdraw';
|
export { WithdrawView } from "./withdraw";
|
||||||
export { FaucetView } from './faucet';
|
export { FaucetView } from "./faucet";
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import React, { } from "react";
|
import React from "react";
|
||||||
import { useLendingReserve } from './../../hooks';
|
import { useLendingReserve } from "./../../hooks";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import './style.less';
|
import "./style.less";
|
||||||
|
|
||||||
import { UserLendingCard } from './../../components/UserLendingCard';
|
import { UserLendingCard } from "./../../components/UserLendingCard";
|
||||||
import { ReserveStatus } from './../../components/ReserveStatus';
|
import { ReserveStatus } from "./../../components/ReserveStatus";
|
||||||
|
|
||||||
export const ReserveView = () => {
|
export const ReserveView = () => {
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
|
@ -15,16 +15,20 @@ export const ReserveView = () => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="reserve-overview">
|
return (
|
||||||
|
<div className="reserve-overview">
|
||||||
<div className="reserve-overview-container">
|
<div className="reserve-overview-container">
|
||||||
<ReserveStatus
|
<ReserveStatus
|
||||||
className="reserve-overview-item reserve-overview-item-left"
|
className="reserve-overview-item reserve-overview-item-left"
|
||||||
reserve={reserve}
|
reserve={reserve}
|
||||||
address={lendingReserve.pubkey} />
|
address={lendingReserve.pubkey}
|
||||||
|
/>
|
||||||
<UserLendingCard
|
<UserLendingCard
|
||||||
className="reserve-overview-item reserve-overview-item-right"
|
className="reserve-overview-item reserve-overview-item-right"
|
||||||
reserve={reserve}
|
reserve={reserve}
|
||||||
address={lendingReserve.pubkey} />
|
address={lendingReserve.pubkey}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import React, { } from "react";
|
import React from "react";
|
||||||
import { useLendingReserve } from '../../hooks';
|
import { useLendingReserve } from "../../hooks";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import './style.less';
|
import "./style.less";
|
||||||
|
|
||||||
import { WithdrawInput } from '../../components/WithdrawInput';
|
import { WithdrawInput } from "../../components/WithdrawInput";
|
||||||
import { DepositInfoLine } from '../../components/DepositInfoLine';
|
import { DepositInfoLine } from "../../components/DepositInfoLine";
|
||||||
import { SideReserveOverview, SideReserveOverviewMode } from '../../components/SideReserveOverview';
|
import {
|
||||||
|
SideReserveOverview,
|
||||||
|
SideReserveOverviewMode,
|
||||||
|
} from "../../components/SideReserveOverview";
|
||||||
|
|
||||||
export const WithdrawView = () => {
|
export const WithdrawView = () => {
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
|
@ -16,21 +19,26 @@ export const WithdrawView = () => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="deposit-reserve">
|
return (
|
||||||
|
<div className="deposit-reserve">
|
||||||
<DepositInfoLine
|
<DepositInfoLine
|
||||||
className="deposit-reserve-item"
|
className="deposit-reserve-item"
|
||||||
reserve={reserve}
|
reserve={reserve}
|
||||||
address={lendingReserve.pubkey} />
|
address={lendingReserve.pubkey}
|
||||||
|
/>
|
||||||
<div className="deposit-reserve-container">
|
<div className="deposit-reserve-container">
|
||||||
<WithdrawInput
|
<WithdrawInput
|
||||||
className="deposit-reserve-item deposit-reserve-item-left"
|
className="deposit-reserve-item deposit-reserve-item-left"
|
||||||
reserve={reserve}
|
reserve={reserve}
|
||||||
address={lendingReserve.pubkey} />
|
address={lendingReserve.pubkey}
|
||||||
|
/>
|
||||||
<SideReserveOverview
|
<SideReserveOverview
|
||||||
className="deposit-reserve-item deposit-reserve-item-right"
|
className="deposit-reserve-item deposit-reserve-item-right"
|
||||||
reserve={reserve}
|
reserve={reserve}
|
||||||
address={lendingReserve.pubkey}
|
address={lendingReserve.pubkey}
|
||||||
mode={SideReserveOverviewMode.Deposit} />
|
mode={SideReserveOverviewMode.Deposit}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue