diff --git a/components/Modal/Action.tsx b/components/Modal/Action.tsx index a47308a6..9e9c9a97 100644 --- a/components/Modal/Action.tsx +++ b/components/Modal/Action.tsx @@ -24,6 +24,8 @@ import { useDegenMode } from "../../hooks/hooks"; import { SubmitButton } from "./components"; import getShadowRecords from "../../api/get-shadows"; import { expandToken, shrinkToken } from "../../store"; +import { getAssets as getAssetSelector } from "../../redux/assetsSelectors"; +import { getAccountPortfolio, getAccountId } from "../../redux/accountSelectors"; export default function Action({ maxBorrowAmount, diff --git a/components/Modal/style.ts b/components/Modal/style.ts index e2ba9596..2b65af3c 100644 --- a/components/Modal/style.ts +++ b/components/Modal/style.ts @@ -8,6 +8,7 @@ export const Wrapper = styled(Box)(({ theme }) => ({ border: "1px solid #4F5178", boxShadow: "0px 0px 10px 4px #00000026", flexDirection: "column", + overflow: "auto", [theme.breakpoints.down("sm")]: { position: "absolute", width: "100%", diff --git a/redux/accountState.ts b/redux/accountState.ts index 158d006e..c1b07d48 100644 --- a/redux/accountState.ts +++ b/redux/accountState.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line import/no-cycle import { IBoosterStaking } from "../interfaces/account"; interface Balance { diff --git a/screens/Staking/modal.tsx b/screens/Staking/modal.tsx new file mode 100644 index 00000000..c18a2dbe --- /dev/null +++ b/screens/Staking/modal.tsx @@ -0,0 +1,234 @@ +// @ts-nocheck +import { useEffect, useState } from "react"; +import { Modal, Stack, Box, Typography, Alert, useTheme } from "@mui/material"; +import LoadingButton from "@mui/lab/LoadingButton"; +import { DateTime } from "luxon"; +import pluralize from "pluralize"; + +import { Input } from "../../components"; +import { CloseButton } from "../../components/Modal/components"; +import { BrrrLogo, Separator } from "./components"; +import { useAppSelector } from "../../redux/hooks"; +import { getTotalBRRR } from "../../redux/selectors/getTotalBRRR"; +import { stake } from "../../store/actions/stake"; +import MonthSlider from "../../components/Slider/staking"; +import Slider from "../../components/Slider"; +import { trackMaxStaking, trackStaking } from "../../utils/telemetry"; +import { useStaking } from "../../hooks/useStaking"; +import { APY_FORMAT, TOKEN_FORMAT } from "../../store"; +import { StakingRewards } from "./rewards"; + +export const StakingModal = ({ open, onClose }) => { + const [total] = useAppSelector(getTotalBRRR); + const [loadingStake, setLoadingStake] = useState(false); + const { + stakingTimestamp, + amount, + months, + setAmount, + setMonths, + stakingNetAPY, + stakingNetTvlAPY, + } = useStaking(); + const unstakeDate = DateTime.fromMillis(stakingTimestamp / 1e6); + const selectedMonths = stakingTimestamp ? Math.round(unstakeDate.diffNow().as("months")) : months; + const theme = useTheme(); + + const invalidAmount = amount > total; + const invalidMonths = months < selectedMonths; + const disabledStake = !amount || invalidAmount || invalidMonths; + + const inputAmount = `${amount}` + .replace(/[^0-9.-]/g, "") + .replace(/(?!^)-/g, "") + .replace(/^0+(\d)/gm, "$1"); + + const sliderValue = Math.round((amount * 100) / Number(total)) || 0; + + const handleMaxClick = () => { + trackMaxStaking({ total }); + setAmount(total); + }; + + const handleInputChange = (e) => { + setAmount(Number(e.target.value)); + }; + + const handleSliderChange = (e) => { + const { value: percent } = e.target; + setAmount((Number(total) * percent) / 100); + }; + + const handleMonthSliderChange = (e) => { + setMonths(e.target.value); + }; + + const handleFocus = (e) => { + e.target.select(); + }; + + const handleStake = () => { + trackStaking({ amount, months, percent: (amount / Number(total)) * 100 }); + stake({ amount, months }); + setLoadingStake(true); + setAmount(0); + }; + + useEffect(() => { + setMonths(selectedMonths); + }, [stakingTimestamp]); + + return ( + + + + + + + Stake BRRR + + + + + + Amount + Available: {total.toLocaleString(undefined, TOKEN_FORMAT)} + + + + + + + + + Duration + + setMonths(12)} + /> + + + + + + + Reward details + + + + Pools APY + + + + {stakingNetAPY.toLocaleString(undefined, APY_FORMAT)}% + + + + + Net Liquidity APY + + + + {stakingNetTvlAPY.toLocaleString(undefined, APY_FORMAT)}% + + + + + + {invalidAmount && ( + Amount must be lower than total BRRR earned + )} + {invalidMonths && ( + + The new staking duration is shorter than the current remaining staking duration + + )} + + + Confirm + + + + Staking duration applies to previously staked BRRR as well. + + + + + + ); +}; diff --git a/utils/index.ts b/utils/index.ts index 3fb684d2..ccba1902 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -65,20 +65,6 @@ export const getBurrow = async ({ hideModal, signOut, }: GetBurrowArgs = {}): Promise => { - /// because it's being called by multiple components on startup - /// all calls wait until setup is complete and then return burrow instance promise - const getBurrowInternal = async () => { - if (burrow) return burrow; - await new Promise((res) => { - setTimeout(() => { - res({}); - }, 250); - }); - return getBurrowInternal(); - }; - // if (!resetBurrow) return getBurrowInternal(); - // resetBurrow = false; - const changeAccount = async (accountId) => { if (fetchData) fetchData(accountId); }; diff --git a/yarn.lock b/yarn.lock index 8883d045..375d20e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16082,4 +16082,4 @@ zustand@4.4.1: zwitch@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/zwitch/-/zwitch-2.0.2.tgz" - integrity sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA== + integrity sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA== \ No newline at end of file