Skip to content

Commit

Permalink
repay function
Browse files Browse the repository at this point in the history
  • Loading branch information
xieqiancaosissi committed Dec 23, 2023
1 parent c58ea1a commit b53dba3
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 61 deletions.
2 changes: 2 additions & 0 deletions components/Modal/Action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,15 @@ export default function Action({ maxBorrowAmount, healthFactor, collateralType }
tokenId,
amount,
extraDecimals,
position: collateralType,
});
} else {
await repay({
tokenId,
amount,
extraDecimals,
isMax,
position: collateralType,
});
}
break;
Expand Down
86 changes: 85 additions & 1 deletion components/Modal/CollateralTypeSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { useAvailableAssets } from "../../hooks/hooks";
import { digitalProcess } from "../../utils/uiNumber";
import { UIAsset } from "../../interfaces";
import { DEFAULT_POSITION } from "../../utils/config";
import { shrinkToken } from "../../store";
import { Asset } from "../../redux/assetState";

export default function CollateralTypeSelector({
export function CollateralTypeSelectorBorrow({
maxBorrowAmountPositions,
selectedCollateralType,
setSelectedCollateralType,
Expand Down Expand Up @@ -88,3 +90,85 @@ export default function CollateralTypeSelector({
</div>
);
}
export function CollateralTypeSelectorRepay({
repayPositions,
selectedCollateralType,
setSelectedCollateralType,
}: {
repayPositions: Record<string, string>;
selectedCollateralType: string;
setSelectedCollateralType: any;
}) {
const [show, setShow] = useState(false);
const assets = useAvailableAssets();
const LPAssetMap = useMemo(() => {
return assets
.filter((asset: UIAsset) => asset.isLpToken)
.reduce((acc, cur) => ({ ...acc, [cur.tokenId]: cur }), {});
}, [assets]);
function getName(position) {
if (position === DEFAULT_POSITION) return "Single token";
const asset: UIAsset = LPAssetMap[position];
const symbols = asset.tokens.reduce(
(acc, cur, index) =>
acc + (cur.metadata?.symbol || "") + (index !== asset.tokens.length - 1 ? "-" : ""),
"",
);
// return `LP token (${symbols})`;
return symbols;
}
return (
<div
className="relative mb-5"
tabIndex={0}
onBlur={() => {
setShow(false);
}}
>
<div className="flex items-center justify-between px-1">
<span className="text-sm text-gray-300 whitespace-nowrap">Collateral Type</span>
<div
className="flex items-center cursor-pointer"
onClick={() => {
setShow(!show);
}}
>
<span className="text-sm text-gray-300 mr-2.5 whitespace-nowrap">
{getName(selectedCollateralType)}
</span>
<ArrowDownIcon className={`${show ? " transform rotate-180" : ""}`} />
</div>
</div>
{/* list */}
<div
className={`absolute border border-dark-500 rounded-md py-3.5 bg-dark-250 w-full z-50 top-8 ${
show ? "" : "hidden"
}`}
>
{/* title */}
<div className="flex items-center justify-between text-sm text-gray-300 px-3.5 mb-2">
<span>Collateral type</span>
<span>Borrowed amount</span>
</div>
{[DEFAULT_POSITION, ...Object.keys(LPAssetMap)].map((position) => {
return (
<div
key={position}
onClick={() => {
setSelectedCollateralType(position);
setShow(false);
}}
className="flex items-center justify-between text-sm text-white h-[46px] hover:bg-gray-950 px-3.5 cursor-pointer"
>
<div className="flex items-center">
<span className="mr-1.5">{getName(position)}</span>
{selectedCollateralType === position ? <CheckedIcon /> : null}
</div>
<span>{digitalProcess(repayPositions[position] || 0, 2)}</span>
</div>
);
})}
</div>
</div>
);
}
10 changes: 10 additions & 0 deletions components/Modal/actionTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { TokenAction } from "../../redux/appSlice";

export const getRepayTemplate = (tokenId, position) => {
const action: TokenAction = "Repay";
return { action, tokenId, amount: "0", position };
};
export const getBorrowTemplate = (tokenId, position) => {
const action: TokenAction = "Borrow";
return { action, tokenId, amount: "0", position };
};
27 changes: 21 additions & 6 deletions components/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useAppSelector, useAppDispatch } from "../../redux/hooks";
import { hideModal, updateAmount } from "../../redux/appSlice";
import { getModalStatus, getAssetData, getSelectedValues } from "../../redux/appSelectors";
import { getWithdrawMaxAmount } from "../../redux/selectors/getWithdrawMaxAmount";
import { getRepayPositions } from "../../redux/selectors/getRepayPositions";
import { getAccountId } from "../../redux/accountSelectors";
import { getBorrowMaxAmount } from "../../redux/selectors/getBorrowMaxAmount";
import { recomputeHealthFactor } from "../../redux/selectors/recomputeHealthFactor";
Expand All @@ -17,7 +18,6 @@ import { recomputeHealthFactorRepay } from "../../redux/selectors/recomputeHealt
import { recomputeHealthFactorRepayFromDeposits } from "../../redux/selectors/recomputeHealthFactorRepayFromDeposits";
import { formatWithCommas_number } from "../../utils/uiNumber";
import { DEFAULT_POSITION } from "../../utils/config";

import { Wrapper } from "./style";
import { getModalData } from "./utils";
import {
Expand All @@ -34,7 +34,10 @@ import Controls from "./Controls";
import Action from "./Action";
import { fetchAssets, fetchRefPrices } from "../../redux/assetsSlice";
import { useDegenMode } from "../../hooks/hooks";
import CollateralTypeSelector from "./CollateralTypeSelector";
import {
CollateralTypeSelectorBorrow,
CollateralTypeSelectorRepay,
} from "./CollateralTypeSelector";

const Modal = () => {
const isOpen = useAppSelector(getModalStatus);
Expand All @@ -46,7 +49,7 @@ const Modal = () => {
const theme = useTheme();
const [selectedCollateralType, setSelectedCollateralType] = useState(DEFAULT_POSITION);

const { action = "Deposit", tokenId } = asset;
const { action = "Deposit", tokenId, position } = asset;

const healthFactor = useAppSelector(
action === "Withdraw"
Expand All @@ -64,7 +67,9 @@ const Modal = () => {
// TODO 计算出每一类资产的最大可借出余额
const maxBorrowAmountPositions = useAppSelector(getBorrowMaxAmount(tokenId));
const maxWithdrawAmount = useAppSelector(getWithdrawMaxAmount(tokenId));
const repayPositions = useAppSelector(getRepayPositions(tokenId));
const maxBorrowAmount = maxBorrowAmountPositions[selectedCollateralType];
const repayAmount = repayPositions[selectedCollateralType];
const {
symbol,
apy,
Expand All @@ -82,14 +87,17 @@ const Modal = () => {
isRepayFromDeposits,
healthFactor,
amount,
borrowed: repayAmount,
});
const total = (price * +amount).toLocaleString(undefined, USD_FORMAT);
const handleClose = () => dispatch(hideModal());
useEffect(() => {
if (isOpen) {
dispatch(fetchAssets()).then(() => dispatch(fetchRefPrices()));
}
}, [isOpen]);
useEffect(() => {
setSelectedCollateralType(position || DEFAULT_POSITION);
}, [position]);
useEffect(() => {
dispatch(updateAmount({ isMax: false, amount: "0" }));
}, [selectedCollateralType]);
Expand All @@ -112,13 +120,20 @@ const Modal = () => {
<Box sx={{ p: ["20px", "20px"] }}>
{!accountId && <NotConnected />}
<ModalTitle asset={asset} onClose={handleClose} />
{action === "Borrow" || action === "Repay" ? (
<CollateralTypeSelector
{action === "Borrow" ? (
<CollateralTypeSelectorBorrow
maxBorrowAmountPositions={maxBorrowAmountPositions}
selectedCollateralType={selectedCollateralType}
setSelectedCollateralType={setSelectedCollateralType}
/>
) : null}
{action === "Repay" ? (
<CollateralTypeSelectorRepay
repayPositions={repayPositions}
selectedCollateralType={selectedCollateralType}
setSelectedCollateralType={setSelectedCollateralType}
/>
) : null}
<RepayTab asset={asset} />
<Controls
amount={amount}
Expand Down
1 change: 1 addition & 0 deletions redux/appSelectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export const getAssetData = createSelector(
return {
tokenId: asset?.token_id,
action: app.selected.action,
position: app.selected.position,
...(asset ? transformAsset(asset, account, assets, app) : {}),
};
},
Expand Down
10 changes: 8 additions & 2 deletions redux/appSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createSlice, PayloadAction, createAsyncThunk } from "@reduxjs/toolkit";
import { getConfig } from "../api";
import { IConfig } from "../interfaces";

type TokenAction = "Supply" | "Borrow" | "Repay" | "Adjust" | "Withdraw";
export type TokenAction = "Supply" | "Borrow" | "Repay" | "Adjust" | "Withdraw";

export type IOrder = "asc" | "desc";

Expand Down Expand Up @@ -45,6 +45,7 @@ export interface AppState {
useAsCollateral: boolean;
amount: string;
isMax: boolean;
position?: string;
};
staking: {
amount: number;
Expand Down Expand Up @@ -143,7 +144,12 @@ export const appSlice = createSlice({
},
showModal(
state,
action: PayloadAction<{ action: TokenAction; amount: string; tokenId: string }>,
action: PayloadAction<{
action: TokenAction;
amount: string;
tokenId: string;
position?: string;
}>,
) {
state.selected = { ...state.selected, isMax: false, ...action.payload };
state.showModal = true;
Expand Down
25 changes: 25 additions & 0 deletions redux/selectors/getRepayPositions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { createSelector } from "@reduxjs/toolkit";
import { RootState } from "../store";
import { hasAssets } from "../utils";
import { shrinkToken } from "../../store";

export const getRepayPositions = (tokenId: string) =>
createSelector(
(state: RootState) => state.app,
(state: RootState) => state.assets,
(state: RootState) => state.account,
(app, assets, account) => {
if (!hasAssets(assets) || !tokenId) return {};
const { positions } = account.portfolio;
const asset = assets.data[tokenId];
return Object.keys(positions).reduce((acc, position) => {
return {
...acc,
[position]: shrinkToken(
positions[position].borrowed[tokenId]?.balance || 0,
asset.metadata.decimals + asset.config.extra_decimals,
),
};
}, {});
},
);
18 changes: 14 additions & 4 deletions screens/TokenDetail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useEffect, useState, createContext, useContext, useMemo } from "react";
import { Modal as MUIModal } from "@mui/material";
import { twMerge } from "tailwind-merge";
import { LayoutBox } from "../../components/LayoutContainer/LayoutContainer";
import { showModal } from "../../redux/appSlice";
import {
ArrowLeft,
SuppliedEmptyIcon,
Expand Down Expand Up @@ -56,6 +57,8 @@ import { useTokenDetails } from "../../hooks/useTokenDetails";
import { IToken } from "../../interfaces/asset";
import LPTokenCell from "./LPTokenCell";
import AvailableBorrowCell from "./AvailableBorrowCell";
import { useAppDispatch } from "../../redux/hooks";
import { getRepayTemplate, getBorrowTemplate } from "../../components/Modal/actionTemplate";

const DetailData = createContext(null) as any;
const TokenDetail = () => {
Expand Down Expand Up @@ -739,7 +742,7 @@ function TokenUserInfo() {
const isWrappedNear = tokenRow.symbol === "NEAR";
const { supplyBalance, maxBorrowAmountPositions } = useUserBalance(tokenId, isWrappedNear);
const handleSupplyClick = useSupplyTrigger(tokenId);
const handleBorrowClick = useBorrowTrigger(tokenId);
const dispatch = useAppDispatch();
function getIcons() {
return (
<div className="flex items-center justify-center flex-wrap flex-shrink-0">
Expand Down Expand Up @@ -829,7 +832,9 @@ function TokenUserInfo() {
<RedSolidButton
disabled={!+totalBorrowAmount}
className="w-1 flex-grow"
onClick={handleBorrowClick}
onClick={() => {
dispatch(showModal(getBorrowTemplate(tokenId, DEFAULT_POSITION)));
}}
>
Borrow
</RedSolidButton>
Expand Down Expand Up @@ -960,7 +965,7 @@ function YouBorrowed() {
},
[[], 0],
) || [[], 0];
const handleRepayClick = useRepayTrigger(tokenId);
const dispatch = useAppDispatch();
const is_empty = !borrowed && !Object.keys(borrowedLp).length;
const borrowedList = { ...borrowedLp };
if (borrowed) {
Expand Down Expand Up @@ -1063,7 +1068,12 @@ function YouBorrowed() {
/>
<Label title="Daily rewards" content={getRewardsReactNode(position)} />
<div className="flex items-center justify-between gap-2 mt-[35px]">
<RedLineButton className="w-1 flex-grow" onClick={handleRepayClick}>
<RedLineButton
className="w-1 flex-grow"
onClick={() => {
dispatch(showModal(getRepayTemplate(tokenId, position)));
}}
>
Repay
</RedLineButton>
</div>
Expand Down
Loading

0 comments on commit b53dba3

Please sign in to comment.