Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.

Revisit tokenaccounts #18

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 59 additions & 27 deletions src/react/components/DealOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,27 @@ import React, { useCallback, useEffect, useState } from "react";
import { useNotify } from "react/hooks/useNotify";
import { useRefresh } from "react/hooks/useRefresh";
import { getClusterTime, getDealAccountData, repayDeal } from "store/api";
import { Deal, DealStatus, RepaymentType } from "types/program.types";
import { Deal, DealStatus } from "types/program.types";
import {
createInterestRepaymentType,
createPrincipalRepaymentType,
getInterestToRepay,
getPrincipalToRepay,
mapDealToStatus,
} from "utils/deal.utils";
import { toUIAmount, toUIPercentage } from "utils/format.utils";
import { toUIAmount, toUIPercentage, toProgramAmount } from "utils/format.utils";
import "../../styles/stakeform.scss";

// TODO: store deal in state instead of every property separately
export const DealOverview = () => {
const wallet = useAnchorWallet();
const [placeholder, setPlaceholder] = useState<string>("Connect wallet");
const [placeholder, setPlaceholder] = useState<string>("CONNECT WALLET");
const connection = useConnection();
const [deal, setDeal] = useState<Deal | undefined>();
const [dealStatus, setDealStatus] = useState<DealStatus | undefined>();
const [amountToRepay, setAmountToRepay] = useState<number | undefined>();
const [repaymentAmount, setRepaymentAmount] = useState<number | undefined>();
const [repaymentType, setRepaymentType] = useState<RepaymentType>(createInterestRepaymentType());
const [repaymentSelectValue, setRepaymentSelectValue] = useState<string>("interest");
const notify = useNotify();
const triggerRefresh = useRefresh();

const fetchDealData = useCallback(async () => {
const _clusterTime = getClusterTime(connection.connection);
Expand All @@ -48,19 +46,31 @@ export const DealOverview = () => {
setDealStatus(dealStatus);
}, [connection.connection, wallet]);

const calculateRepaymentAmount = useCallback(() => {
const triggerRefresh = useRefresh(fetchDealData);

const determineRepaymentType = useCallback(() => {
if (!deal) {
setRepaymentAmount(0);
return;
}

const interestToRepay = getInterestToRepay(deal);

setRepaymentSelectValue(
repaymentSelectValue === "interest" && interestToRepay ? "interest" : "principal"
);
}, [deal, repaymentSelectValue]);

const calculateAmountToRepay = useCallback(() => {
if (!deal) {
return;
}
switch (repaymentSelectValue) {
case "interest": {
setRepaymentAmount(getInterestToRepay(deal));
setAmountToRepay(getInterestToRepay(deal));
break;
}
default:
setRepaymentAmount(getPrincipalToRepay(deal));
setAmountToRepay(getPrincipalToRepay(deal));
}
}, [repaymentSelectValue, deal]);

Expand All @@ -77,24 +87,34 @@ export const DealOverview = () => {
}, [connection.connection, wallet?.publicKey, fetchDealData]);

useEffect(() => {
calculateRepaymentAmount();
}, [calculateRepaymentAmount]);
calculateAmountToRepay();
}, [calculateAmountToRepay]);

useEffect(() => {
determineRepaymentType();
}, [determineRepaymentType]);

const onSubmit = async (e: React.SyntheticEvent) => {
e.preventDefault();

if (!repaymentAmount) {
if (!repaymentAmount || !amountToRepay) {
return;
}

try {
await repayDeal(repaymentAmount, repaymentType, connection.connection, wallet as Wallet);
calculateAmountToRepay();
const repaymentTypeObj =
repaymentSelectValue === "interest"
? createInterestRepaymentType()
: createPrincipalRepaymentType();
await repayDeal(repaymentAmount, repaymentTypeObj, connection.connection, wallet as Wallet);
const showFeeNotification = repaymentSelectValue === "interest";
const paymentNotification = `Successfully repaid ${toUIAmount(repaymentAmount)} USDC`;
const paymentNotification = `Successfully repaid ${toUIAmount(Math.min(repaymentAmount, amountToRepay))} USDC`;
const feeNotification = ` with a ${toUIAmount(
repaymentAmount * FEES.INTEREST_PAYMENT
Math.min(repaymentAmount, amountToRepay) * FEES.INTEREST_PAYMENT
)} USDC fee`;
notify("success", `${paymentNotification}${showFeeNotification ? feeNotification : ""}`);
setRepaymentAmount(undefined);
triggerRefresh();
} catch (e: any) {
notify("error", `Transaction failed! ${e?.message}`);
Expand All @@ -108,17 +128,23 @@ export const DealOverview = () => {

const onRepaymentTypeChange = (e: any) => {
if (repaymentSelectValue !== e.target.value) {
switch (e.target.value) {
case "interest":
setRepaymentType(createInterestRepaymentType());
break;
default:
setRepaymentType(createPrincipalRepaymentType());
}
setRepaymentSelectValue(e.target.value);
setRepaymentAmount(undefined);
}
};

const onChange = (
e: React.ChangeEvent<HTMLInputElement>,
setter: (val: number | undefined) => any
) => {
const newValue = e.target.value === "" ? undefined : toProgramAmount(Number(e.target.value));
setter(newValue);
};

const onChangeRepaymentAmount = (e: React.ChangeEvent<HTMLInputElement>) => {
onChange(e, setRepaymentAmount);
};

return (
<div>
<h2>Your deal</h2>
Expand All @@ -138,6 +164,7 @@ export const DealOverview = () => {
<br />
<label className="stake-input-label">
Principal
<p>The total amount of USDC to borrow</p>
<input
name="principal"
type="number"
Expand All @@ -151,6 +178,7 @@ export const DealOverview = () => {
<br />
<label className="stake-input-label">
Financing Fee %
<p>The percentage on top of the principal that needs to be repaid as interest</p>
<input
name="financingFee"
type="number"
Expand All @@ -173,19 +201,23 @@ export const DealOverview = () => {
value={repaymentSelectValue}
className="repayment-select credix-button MuiButton-root"
>
<MenuItem value="principal">Principal</MenuItem>
<MenuItem value="interest">Interest</MenuItem>
<MenuItem value="principal" disabled={!deal || !getPrincipalToRepay(deal)}>
Principal
</MenuItem>
<MenuItem value="interest" disabled={!deal || !getInterestToRepay(deal)}>
Interest
</MenuItem>
</Select>
</label>
<br />
<label className="stake-input-label">
USDC amount
<p>To repay: {amountToRepay === undefined ? "" : toUIAmount(amountToRepay)} USDC</p>
<input
name="repayment"
type="number"
disabled={!canSubmit()}
readOnly={true}
placeholder={placeholder}
onChange={onChangeRepaymentAmount}
value={repaymentAmount === undefined ? "" : toUIAmount(repaymentAmount)}
className="stake-input credix-button MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary balance-button"
/>
Expand Down
4 changes: 2 additions & 2 deletions src/react/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import "../../styles/footer.scss";
export const Footer = () => (
<div>
<div className="footer footer-left">
<Link to={Path.OVERVIEW}>Pool</Link>
<Link to={Path.DEALS}>Deals</Link>
<Link to={Path.OVERVIEW}>Invest</Link>
<Link to={Path.DEALS}>Borrow/Repay</Link>
<Link to={Path.HELP} className="start-here animated bounce">
Start here
</Link>
Expand Down
33 changes: 8 additions & 25 deletions src/react/components/forms/CreateDealForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ import { useAnchorWallet, useConnection } from "@solana/wallet-adapter-react";
import { serialAsync } from "utils/async.utils";
import React, { useEffect, useState } from "react";
import { useNotify } from "react/hooks/useNotify";
import { activateDeal, createDeal, getUserUSDCTokenAccount } from "store/api";
import { activateDeal, createDeal } from "store/api";
import "../../../styles/stakeform.scss";
import { PublicKey } from "@solana/web3.js";
import { useRefresh } from "react/hooks/useRefresh";

interface Props {
disabled?: boolean;
}

export const CreateDealForm = (props: Props) => {
export const CreateDealForm = () => {
const wallet = useAnchorWallet();
const connection = useConnection();
const [principal, setPrincipal] = useState<number | undefined>();
Expand Down Expand Up @@ -55,17 +51,6 @@ export const CreateDealForm = (props: Props) => {
return;
}

const depositorLiquidityPoolTokenAccount = await getUserUSDCTokenAccount(
connection.connection,
wallet as Wallet
);

// Can't we just create a token account using the associated token program when it doesn't exist yet?
if (!depositorLiquidityPoolTokenAccount) {
notify("error", "Please opt in for USDC in your wallet");
return;
}

try {
await createDeal(
principal,
Expand Down Expand Up @@ -95,9 +80,7 @@ export const CreateDealForm = (props: Props) => {
validKey = false; // can't have an empty block..
}

return (
wallet?.publicKey && principal && financingFee && borrower && validKey && !props.disabled
);
return wallet?.publicKey && principal && financingFee && borrower && validKey;
};

const onChange = (
Expand Down Expand Up @@ -142,7 +125,7 @@ export const CreateDealForm = (props: Props) => {
value={borrower}
placeholder={placeholder}
onChange={onChangeBorrower}
disabled={!wallet?.publicKey || props.disabled}
disabled={!wallet?.publicKey}
className="stake-input borrower-pk credix-button MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary balance-button"
/>
</label>
Expand All @@ -155,7 +138,7 @@ export const CreateDealForm = (props: Props) => {
value={principal === undefined ? "" : principal}
placeholder={placeholder}
onChange={onChangePrincipal}
disabled={!wallet?.publicKey || props.disabled}
disabled={!wallet?.publicKey}
className="stake-input credix-button MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary balance-button"
/>
</label>
Expand All @@ -168,7 +151,7 @@ export const CreateDealForm = (props: Props) => {
value={financingFee === undefined ? "" : financingFee}
placeholder={placeholder}
onChange={onChangeFinancingFee}
disabled={!wallet?.publicKey || props.disabled}
disabled={!wallet?.publicKey}
className="stake-input credix-button MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary balance-button"
/>
</label>
Expand All @@ -183,15 +166,15 @@ export const CreateDealForm = (props: Props) => {
placeholder={placeholder}
onChange={onChangeTimeToMaturity}
onBlur={onBlurTimeToMaturity}
disabled={!wallet?.publicKey || props.disabled}
disabled={!wallet?.publicKey}
className="stake-input credix-button MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary balance-button"
/>
</label>
<br />
<input
type="submit"
disabled={!canSubmit()}
value={props.disabled ? "Max deals reached" : "Create Deal"}
value="Create Deal"
className="stake-submit credix-button MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary balance-button"
/>
</form>
Expand Down
Loading