mirror of https://github.com/certusone/oyster.git
feat: add sliders
This commit is contained in:
parent
2bd278fd41
commit
d400f85203
11
README.md
11
README.md
|
@ -15,14 +15,9 @@ Any content produced by Solana, or developer resources that Solana provides, are
|
||||||
- [] Facuet add USDC that is using sol airdrop and USDC reserve to give user USDC
|
- [] Facuet add USDC that is using sol airdrop and USDC reserve to give user USDC
|
||||||
- [] Borrow - Convert target ccy to collateral on oposite side
|
- [] Borrow - Convert target ccy to collateral on oposite side
|
||||||
- [] Borrow - liquidity token wrapped SOL should be unwrapped ...
|
- [] Borrow - liquidity token wrapped SOL should be unwrapped ...
|
||||||
- [] Fix slider on repay page
|
- [x] Fix slider on repay page
|
||||||
- [] Add slider to borrow page (100% max collateral)
|
- [x] Add slider to borrow page (100% max collateral)
|
||||||
- [] Add market size on front page
|
- [x] Add market size on front page
|
||||||
- [] Add github link
|
- [] Add github link
|
||||||
- [] Repay from reserve (add selection for obligation/loan)
|
- [] Repay from reserve (add selection for obligation/loan)
|
||||||
- [] Add support for token names in URL in addition to reserve address
|
- [] Add support for token names in URL in addition to reserve address
|
||||||
|
|
||||||
# TOP for tomorrow
|
|
||||||
|
|
||||||
- subscribe to all dex markets that are used by lending reserves
|
|
||||||
- finish reserve overivew
|
|
||||||
|
|
|
@ -260,6 +260,10 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-slider {
|
||||||
|
margin: 20px 15px 40px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
.token-input {
|
.token-input {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -28,9 +28,6 @@ export const deposit = async (
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
wallet: any
|
wallet: any
|
||||||
) => {
|
) => {
|
||||||
// TODO: customize ?
|
|
||||||
const MAX_UTILIZATION_RATE = 80;
|
|
||||||
|
|
||||||
notify({
|
notify({
|
||||||
message: "Depositing funds...",
|
message: "Depositing funds...",
|
||||||
description: "Please review transactions to approve.",
|
description: "Please review transactions to approve.",
|
||||||
|
@ -110,6 +107,7 @@ export const deposit = async (
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// TODO: finish reserve init
|
// TODO: finish reserve init
|
||||||
|
const MAX_UTILIZATION_RATE = 80;
|
||||||
instructions.push(
|
instructions.push(
|
||||||
initReserveInstruction(
|
initReserveInstruction(
|
||||||
amountLamports,
|
amountLamports,
|
||||||
|
|
|
@ -109,22 +109,18 @@ export const repay = async (
|
||||||
authority
|
authority
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let tx = await sendTransaction(
|
||||||
|
connection,
|
||||||
|
wallet,
|
||||||
|
instructions.concat(cleanupInstructions),
|
||||||
|
signers,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
notify({
|
||||||
let tx = await sendTransaction(
|
message: "Funds repaid.",
|
||||||
connection,
|
type: "success",
|
||||||
wallet,
|
description: `Transaction - ${tx}`,
|
||||||
instructions.concat(cleanupInstructions),
|
});
|
||||||
signers,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
notify({
|
|
||||||
message: "Funds repaid.",
|
|
||||||
type: "success",
|
|
||||||
description: `Transaction - ${tx}`,
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
// TODO:
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
LendingReserveParser,
|
LendingReserveParser,
|
||||||
} from "../../models";
|
} from "../../models";
|
||||||
import { TokenIcon } from "../TokenIcon";
|
import { TokenIcon } from "../TokenIcon";
|
||||||
import { Button, Card, Spin } from "antd";
|
import { Button, Card } from "antd";
|
||||||
import { cache, ParsedAccount } from "../../contexts/accounts";
|
import { cache, ParsedAccount } from "../../contexts/accounts";
|
||||||
import { NumericInput } from "../Input/numeric";
|
import { NumericInput } from "../Input/numeric";
|
||||||
import { useConnection } from "../../contexts/connection";
|
import { useConnection } from "../../contexts/connection";
|
||||||
|
@ -19,12 +19,9 @@ import { borrow } from "../../actions";
|
||||||
import { CollateralSelector } from "./../CollateralSelector";
|
import { CollateralSelector } from "./../CollateralSelector";
|
||||||
import "./style.less";
|
import "./style.less";
|
||||||
import { LABELS } from "../../constants";
|
import { LABELS } from "../../constants";
|
||||||
import { LoadingOutlined } from "@ant-design/icons";
|
|
||||||
import { ActionConfirmation } from "./../ActionConfirmation";
|
import { ActionConfirmation } from "./../ActionConfirmation";
|
||||||
import { BackButton } from "./../BackButton";
|
import { BackButton } from "./../BackButton";
|
||||||
|
|
||||||
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />;
|
|
||||||
|
|
||||||
export const BorrowInput = (props: {
|
export const BorrowInput = (props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
reserve: ParsedAccount<LendingReserve>;
|
reserve: ParsedAccount<LendingReserve>;
|
||||||
|
@ -154,12 +151,10 @@ export const BorrowInput = (props: {
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={onBorrow}
|
onClick={onBorrow}
|
||||||
disabled={fromAccounts.length === 0 || pendingTx}
|
loading={pendingTx}
|
||||||
|
disabled={fromAccounts.length === 0}
|
||||||
>
|
>
|
||||||
{LABELS.BORROW_ACTION}
|
{LABELS.BORROW_ACTION}
|
||||||
{pendingTx && (
|
|
||||||
<Spin indicator={antIcon} className="action-spinner" />
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,19 +7,16 @@ import {
|
||||||
} from "../../hooks";
|
} from "../../hooks";
|
||||||
import { LendingReserve } from "../../models/lending";
|
import { LendingReserve } from "../../models/lending";
|
||||||
import { TokenIcon } from "../TokenIcon";
|
import { TokenIcon } from "../TokenIcon";
|
||||||
import { Button, Card, Slider, Spin } from "antd";
|
import { Button, Card, Slider } 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";
|
||||||
import { LoadingOutlined } from "@ant-design/icons";
|
|
||||||
import { ActionConfirmation } from "./../ActionConfirmation";
|
import { ActionConfirmation } from "./../ActionConfirmation";
|
||||||
import { LABELS, marks } from "../../constants";
|
import { LABELS, marks } from "../../constants";
|
||||||
|
|
||||||
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />;
|
|
||||||
|
|
||||||
export const DepositInput = (props: {
|
export const DepositInput = (props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
reserve: LendingReserve;
|
reserve: LendingReserve;
|
||||||
|
@ -134,12 +131,10 @@ export const DepositInput = (props: {
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={onDeposit}
|
onClick={onDeposit}
|
||||||
disabled={fromAccounts.length === 0 || pendingTx}
|
loading={pendingTx}
|
||||||
|
disabled={fromAccounts.length === 0}
|
||||||
>
|
>
|
||||||
{LABELS.DEPOSIT_ACTION}
|
{LABELS.DEPOSIT_ACTION}
|
||||||
{pendingTx && (
|
|
||||||
<Spin indicator={antIcon} className="action-spinner" />
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
LendingReserveParser,
|
LendingReserveParser,
|
||||||
} from "../../models";
|
} from "../../models";
|
||||||
import { TokenIcon } from "../TokenIcon";
|
import { TokenIcon } from "../TokenIcon";
|
||||||
import { Button, Card, Slider, Spin } from "antd";
|
import { Button, Card, Slider } from "antd";
|
||||||
import { cache, ParsedAccount, useMint } from "../../contexts/accounts";
|
import { cache, ParsedAccount, useMint } from "../../contexts/accounts";
|
||||||
import { NumericInput } from "../Input/numeric";
|
import { NumericInput } from "../Input/numeric";
|
||||||
import { useConnection } from "../../contexts/connection";
|
import { useConnection } from "../../contexts/connection";
|
||||||
|
@ -15,15 +15,14 @@ import { repay } from "../../actions";
|
||||||
import { CollateralSelector } from "./../CollateralSelector";
|
import { CollateralSelector } from "./../CollateralSelector";
|
||||||
import "./style.less";
|
import "./style.less";
|
||||||
import { LABELS, marks } from "../../constants";
|
import { LABELS, marks } from "../../constants";
|
||||||
import { LoadingOutlined } from "@ant-design/icons";
|
|
||||||
import { ActionConfirmation } from "./../ActionConfirmation";
|
import { ActionConfirmation } from "./../ActionConfirmation";
|
||||||
|
import { fromLamports, wadToLamports } from "../../utils/utils";
|
||||||
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />;
|
import { notify } from "../../utils/notifications";
|
||||||
|
|
||||||
export const RepayInput = (props: {
|
export const RepayInput = (props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
reserve: ParsedAccount<LendingReserve>;
|
reserve: ParsedAccount<LendingReserve>;
|
||||||
obligation?: ParsedAccount<LendingObligation>;
|
obligation: ParsedAccount<LendingObligation>;
|
||||||
}) => {
|
}) => {
|
||||||
const connection = useConnection();
|
const connection = useConnection();
|
||||||
const { wallet } = useWallet();
|
const { wallet } = useWallet();
|
||||||
|
@ -33,6 +32,14 @@ export const RepayInput = (props: {
|
||||||
const repayReserve = props.reserve;
|
const repayReserve = props.reserve;
|
||||||
const obligation = props.obligation;
|
const obligation = props.obligation;
|
||||||
|
|
||||||
|
const liquidityMint = useMint(repayReserve.info.liquidityMint);
|
||||||
|
|
||||||
|
const borrowAmountLamports = wadToLamports(obligation.info.borrowAmountWad).toNumber();
|
||||||
|
const borrowAmount = fromLamports(
|
||||||
|
borrowAmountLamports,
|
||||||
|
liquidityMint
|
||||||
|
);
|
||||||
|
|
||||||
const [collateralReserveMint, setCollateralReserveMint] = useState<string>();
|
const [collateralReserveMint, setCollateralReserveMint] = useState<string>();
|
||||||
|
|
||||||
const collateralReserve = useMemo(() => {
|
const collateralReserve = useMemo(() => {
|
||||||
|
@ -49,20 +56,17 @@ export const RepayInput = (props: {
|
||||||
repayReserve.info.liquidityMint
|
repayReserve.info.liquidityMint
|
||||||
);
|
);
|
||||||
|
|
||||||
const repayLiquidityMint = useMint(repayReserve.info.liquidityMint);
|
|
||||||
// const collateralBalance = useUserBalance(reserve?.collateralMint);
|
|
||||||
|
|
||||||
const obligationAccount = useAccountByMint(obligation?.info.tokenMint);
|
const obligationAccount = useAccountByMint(obligation?.info.tokenMint);
|
||||||
|
|
||||||
const convert = useCallback(
|
const convert = useCallback(
|
||||||
(val: string | number) => {
|
(val: string | number) => {
|
||||||
if (typeof val === "string") {
|
if (typeof val === "string") {
|
||||||
return (parseFloat(val) / balance) * 100;
|
return (parseFloat(val) / borrowAmount) * 100;
|
||||||
} else {
|
} else {
|
||||||
return ((val * balance) / 100).toFixed(2);
|
return ((val * borrowAmount) / 100).toFixed(2);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[balance]
|
[borrowAmount]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { value, setValue, mark, setMark, type } = useSliderInput(convert);
|
const { value, setValue, mark, setMark, type } = useSliderInput(convert);
|
||||||
|
@ -81,11 +85,13 @@ export const RepayInput = (props: {
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
|
const toRepayLamports = type === InputType.Slider
|
||||||
|
? (mark * borrowAmountLamports) / 100
|
||||||
|
: Math.ceil(borrowAmountLamports * (parseFloat(value) / borrowAmount));
|
||||||
|
|
||||||
await repay(
|
await repay(
|
||||||
fromAccounts[0],
|
fromAccounts[0],
|
||||||
type === InputType.Slider
|
toRepayLamports,
|
||||||
? (mark * balanceLamports) / 100
|
|
||||||
: Math.ceil(balanceLamports * (parseFloat(value) / balance)),
|
|
||||||
obligation,
|
obligation,
|
||||||
obligationAccount,
|
obligationAccount,
|
||||||
repayReserve,
|
repayReserve,
|
||||||
|
@ -96,8 +102,13 @@ export const RepayInput = (props: {
|
||||||
|
|
||||||
setValue("");
|
setValue("");
|
||||||
setShowConfirmation(true);
|
setShowConfirmation(true);
|
||||||
} catch {
|
} catch (error) {
|
||||||
// TODO:
|
notify({
|
||||||
|
message: "Unable to repay loan.",
|
||||||
|
type: "error",
|
||||||
|
description: error.message,
|
||||||
|
});
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
setPendingTx(false);
|
setPendingTx(false);
|
||||||
}
|
}
|
||||||
|
@ -105,7 +116,8 @@ export const RepayInput = (props: {
|
||||||
}, [
|
}, [
|
||||||
mark,
|
mark,
|
||||||
value,
|
value,
|
||||||
balance,
|
borrowAmount,
|
||||||
|
borrowAmountLamports,
|
||||||
balanceLamports,
|
balanceLamports,
|
||||||
type,
|
type,
|
||||||
connection,
|
connection,
|
||||||
|
@ -171,12 +183,10 @@ export const RepayInput = (props: {
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={onRepay}
|
onClick={onRepay}
|
||||||
|
loading={pendingTx}
|
||||||
disabled={fromAccounts.length === 0}
|
disabled={fromAccounts.length === 0}
|
||||||
>
|
>
|
||||||
{LABELS.REPAY_ACTION}
|
{LABELS.REPAY_ACTION}
|
||||||
{pendingTx && (
|
|
||||||
<Spin indicator={antIcon} className="action-spinner" />
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
} from "../../hooks";
|
} from "../../hooks";
|
||||||
import { LendingReserve } from "../../models/lending";
|
import { LendingReserve } from "../../models/lending";
|
||||||
import { TokenIcon } from "../TokenIcon";
|
import { TokenIcon } from "../TokenIcon";
|
||||||
import { Button, Card, Slider, Spin } from "antd";
|
import { Button, Card, Slider } 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";
|
||||||
|
@ -16,11 +16,8 @@ import { withdraw } from "../../actions";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import "./style.less";
|
import "./style.less";
|
||||||
import { LABELS, marks } from "../../constants";
|
import { LABELS, marks } from "../../constants";
|
||||||
import { LoadingOutlined } from "@ant-design/icons";
|
|
||||||
import { ActionConfirmation } from "./../ActionConfirmation";
|
import { ActionConfirmation } from "./../ActionConfirmation";
|
||||||
|
|
||||||
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />;
|
|
||||||
|
|
||||||
export const WithdrawInput = (props: {
|
export const WithdrawInput = (props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
reserve: LendingReserve;
|
reserve: LendingReserve;
|
||||||
|
@ -140,12 +137,10 @@ export const WithdrawInput = (props: {
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={onWithdraw}
|
onClick={onWithdraw}
|
||||||
disabled={fromAccounts.length === 0 || pendingTx}
|
loading={pendingTx}
|
||||||
|
disabled={fromAccounts.length === 0}
|
||||||
>
|
>
|
||||||
{LABELS.WITHDRAW_ACTION}
|
{LABELS.WITHDRAW_ACTION}
|
||||||
{pendingTx && (
|
|
||||||
<Spin indicator={antIcon} className="action-spinner" />
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -22,9 +22,7 @@ export const RepayReserveView = () => {
|
||||||
);
|
);
|
||||||
const reserve = lendingReserve?.info;
|
const reserve = lendingReserve?.info;
|
||||||
|
|
||||||
console.log([reserveId, obligationId]);
|
if (!reserve || !lendingReserve || !lendingObligation) {
|
||||||
|
|
||||||
if (!reserve || !lendingReserve) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue