diff --git a/public/splash.svg b/public/splash.svg new file mode 100644 index 0000000..d32518e --- /dev/null +++ b/public/splash.svg @@ -0,0 +1,2222 @@ + +image/svg+xml diff --git a/src/App.less b/src/App.less index 10e2872..ebd44c5 100644 --- a/src/App.less +++ b/src/App.less @@ -17,7 +17,10 @@ body { .footer { background-color: black; color: lightgray; - padding: 20px; + padding: 10px 10px; + max-height: 60px; + overflow: hidden; + text-overflow: ellipsis; } .action-spinner { @@ -156,7 +159,6 @@ body { } .wallet-wrapper { - background: @background-color-base; padding-left: 0.7rem; border-radius: 0.5rem; display: flex; @@ -165,7 +167,6 @@ body { } .wallet-key { - background: @background-color-base; padding: 0.1rem 0.5rem 0.1rem 0.7rem; margin-left: 0.3rem; border-radius: 0.5rem; @@ -268,6 +269,27 @@ body { padding: 8px 8px; } +.ant-pro-global-header { + .ant-pro-global-header-logo a h1 { + color: white !important; + } + + background-color: black !important; + color: white !important; + + .ant-btn { + color: white !important; + } +} + +.ant-statistic { + user-select: none; +} + +.ant-statistic-content { + font-weight: bold; +} + .token-input { display: flex; align-items: center; diff --git a/src/actions/borrow.tsx b/src/actions/borrow.tsx index 741e229..6f3018c 100644 --- a/src/actions/borrow.tsx +++ b/src/actions/borrow.tsx @@ -61,31 +61,31 @@ export const borrow = async ( const obligation = existingObligation ? existingObligation.pubkey : createUninitializedObligation( - instructions, - wallet.publicKey, - await connection.getMinimumBalanceForRentExemption( - LendingObligationLayout.span - ), - signers - ); + instructions, + wallet.publicKey, + await connection.getMinimumBalanceForRentExemption( + LendingObligationLayout.span + ), + signers + ); const obligationMint = existingObligation ? existingObligation.info.tokenMint : createUninitializedMint( - instructions, - wallet.publicKey, - await connection.getMinimumBalanceForRentExemption(MintLayout.span), - signers - ); + instructions, + wallet.publicKey, + await connection.getMinimumBalanceForRentExemption(MintLayout.span), + signers + ); const obligationTokenOutput = obligationAccount ? obligationAccount : createUninitializedAccount( - instructions, - wallet.publicKey, - accountRentExempt, - signers - ); + instructions, + wallet.publicKey, + accountRentExempt, + signers + ); let toAccount = await findOrCreateAccountByMint( wallet.publicKey, @@ -172,10 +172,6 @@ export const borrow = async ( ) ); - const market = cache.get(depositReserve.info.lendingMarket) as ParsedAccount< - LendingMarket - >; - const dexMarketAddress = borrowReserve.info.dexMarketOption ? borrowReserve.info.dexMarket : depositReserve.info.dexMarket; @@ -185,6 +181,9 @@ export const borrow = async ( throw new Error(`Dex market doesn't exist.`); } + const market = cache.get(depositReserve.info.lendingMarket) as ParsedAccount< + LendingMarket + >; const dexOrderBookSide = market.info.quoteMint.equals( depositReserve.info.liquidityMint ) diff --git a/src/actions/index.ts b/src/actions/index.ts index 08e7609..4d9e5bd 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -2,4 +2,5 @@ export { borrow } from "./borrow"; export { deposit } from "./deposit"; export { repay } from "./repay"; export { withdraw } from "./withdraw"; +export { liquidate } from "./liquidate"; export * from "./account"; diff --git a/src/actions/liquidate.tsx b/src/actions/liquidate.tsx new file mode 100644 index 0000000..7f4df60 --- /dev/null +++ b/src/actions/liquidate.tsx @@ -0,0 +1,141 @@ +import { + Account, + Connection, + PublicKey, + TransactionInstruction, +} from "@solana/web3.js"; +import { sendTransaction } from "../contexts/connection"; +import { notify } from "../utils/notifications"; +import { LendingReserve } from "./../models/lending/reserve"; +import { liquidateInstruction } from "./../models/lending/liquidate"; +import { AccountLayout, Token } from "@solana/spl-token"; +import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../constants/ids"; +import { createTempMemoryAccount, ensureSplAccount, findOrCreateAccountByMint } from "./account"; +import { LendingMarket, LendingObligation, TokenAccount } from "../models"; +import { cache, ParsedAccount } from "../contexts/accounts"; + +export const liquidate = async ( + + connection: Connection, + wallet: any, + from: TokenAccount, // liquidity account + amountLamports: number, // in liquidty token (lamports) + + // which loan to repay + obligation: ParsedAccount, + + repayReserve: ParsedAccount, + + withdrawReserve: ParsedAccount, +) => { + notify({ + message: "Repaing funds...", + description: "Please review transactions to approve.", + type: "warn", + }); + + // user from account + const signers: Account[] = []; + const instructions: TransactionInstruction[] = []; + const cleanupInstructions: TransactionInstruction[] = []; + + const accountRentExempt = await connection.getMinimumBalanceForRentExemption( + AccountLayout.span + ); + + const [authority] = await PublicKey.findProgramAddress( + [repayReserve.info.lendingMarket.toBuffer()], + LENDING_PROGRAM_ID + ); + + const fromAccount = ensureSplAccount( + instructions, + cleanupInstructions, + from, + wallet.publicKey, + amountLamports + accountRentExempt, + signers + ); + + // create approval for transfer transactions + instructions.push( + Token.createApproveInstruction( + TOKEN_PROGRAM_ID, + fromAccount, + authority, + wallet.publicKey, + [], + amountLamports + ) + ); + + // get destination account + const toAccount = await findOrCreateAccountByMint( + wallet.publicKey, + wallet.publicKey, + instructions, + cleanupInstructions, + accountRentExempt, + withdrawReserve.info.collateralMint, + signers + ); + + const dexMarketAddress = repayReserve.info.dexMarketOption + ? repayReserve.info.dexMarket + : withdrawReserve.info.dexMarket; + const dexMarket = cache.get(dexMarketAddress); + + if (!dexMarket) { + throw new Error(`Dex market doesn't exist.`); + } + + const market = cache.get(withdrawReserve.info.lendingMarket) as ParsedAccount< + LendingMarket + >; + + const dexOrderBookSide = market.info.quoteMint.equals( + repayReserve.info.liquidityMint + ) + ? dexMarket?.info.bids + : dexMarket?.info.asks; + + + console.log(dexMarketAddress.toBase58()) + + const memory = createTempMemoryAccount( + instructions, + wallet.publicKey, + signers + ); + + instructions.push( + liquidateInstruction( + amountLamports, + fromAccount, + toAccount, + repayReserve.pubkey, + repayReserve.info.liquiditySupply, + withdrawReserve.pubkey, + withdrawReserve.info.collateralSupply, + obligation.pubkey, + authority, + dexMarketAddress, + dexOrderBookSide, + memory + ) + ); + + let tx = await sendTransaction( + connection, + wallet, + instructions.concat(cleanupInstructions), + signers, + true + ); + + notify({ + message: "Funds liquidated.", + type: "success", + description: `Transaction - ${tx}`, + }); +}; diff --git a/src/components/BarChartStatistic/index.tsx b/src/components/BarChartStatistic/index.tsx new file mode 100644 index 0000000..21128e5 --- /dev/null +++ b/src/components/BarChartStatistic/index.tsx @@ -0,0 +1,40 @@ +import { Statistic } from "antd"; +import React, { } from "react"; + +export const BarChartStatistic = (props: { + items: T[]; + title: string; + name: (item: T) => string; + getPct: (item: T) => number; +}) => { + const colors = [ + '#003f5c', + '#2f4b7c', + '#665191', + '#a05195', + '#d45087', + '#f95d6a', + '#ff7c43', + '#ffa600', + ].reverse(); + + return ( + +
+ {props.items.map((item, i) => +
+ {props.name(item)} +
)} +
} + > +
+ ); +}; diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index e25612b..9f1d565 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -42,7 +42,7 @@ export const AppLayout = (props: any) => {
{LABELS.FOOTER}
} + footerRender={() =>
{LABELS.FOOTER}
} navTheme={theme} headerTheme={theme} theme={theme} diff --git a/src/components/LiquidateInput/index.tsx b/src/components/LiquidateInput/index.tsx index 182cd93..ecaea5a 100644 --- a/src/components/LiquidateInput/index.tsx +++ b/src/components/LiquidateInput/index.tsx @@ -4,25 +4,61 @@ import React, { useCallback } from "react"; import { useState } from "react"; import { LABELS } from "../../constants"; import { ParsedAccount } from "../../contexts/accounts"; -import { EnrichedLendingObligation } from "../../hooks"; +import { EnrichedLendingObligation, useUserBalance } from "../../hooks"; import { LendingReserve } from "../../models"; +import { ActionConfirmation } from "../ActionConfirmation"; import { BackButton } from "../BackButton"; import { CollateralSelector } from "../CollateralSelector"; +import { liquidate } from "../../actions"; import "./style.less"; +import { useConnection } from "../../contexts/connection"; +import { useWallet } from "../../contexts/wallet"; +import { wadToLamports } from "../../utils/utils"; export const LiquidateInput = (props: { className?: string; - reserve: ParsedAccount; - collateralReserve?: ParsedAccount; + repayReserve: ParsedAccount; + withdrawReserve?: ParsedAccount; obligation: EnrichedLendingObligation; }) => { - const { reserve, collateralReserve } = props; + const connection = useConnection(); + const { wallet } = useWallet(); + const { repayReserve, withdrawReserve, obligation } = props; const [pendingTx, setPendingTx] = useState(false); + const [showConfirmation, setShowConfirmation] = useState(false); + + const { accounts: fromAccounts } = useUserBalance( + repayReserve?.info.liquidityMint + ); const onLiquidate = useCallback(() => { + if (!withdrawReserve) { + return; + } + setPendingTx(true); - setPendingTx(false); - }, []); + + (async () => { + try { + await liquidate( + connection, + wallet, + fromAccounts[0], + // TODO: ensure user has available amount + wadToLamports(obligation.info.borrowAmountWad).toNumber(), + obligation.account, + repayReserve, + withdrawReserve, + ); + + setShowConfirmation(true); + } catch { + // TODO: + } finally { + setPendingTx(false); + } + })(); + }, [withdrawReserve, fromAccounts, obligation, repayReserve, wallet, connection]); const bodyStyle: React.CSSProperties = { display: "flex", @@ -34,24 +70,30 @@ export const LiquidateInput = (props: { return ( -
-
{LABELS.SELECT_COLLATERAL}
- - - -
+ {showConfirmation ? ( + setShowConfirmation(false)} /> + ) : ( +
+
{LABELS.SELECT_COLLATERAL}
+ + + +
)}
); }; diff --git a/src/views/dashboard/deposit/index.tsx b/src/views/dashboard/deposit/index.tsx new file mode 100644 index 0000000..027766a --- /dev/null +++ b/src/views/dashboard/deposit/index.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import { LABELS } from "../../../constants"; +import { useUserDeposits } from "./../../../hooks"; +import { DepositItem } from "./item"; + +export const DashboardDeposits = () => { + const { userDeposits } = useUserDeposits(); + + return (<> + {LABELS.DASHBOARD_TITLE_DEPOSITS} +
+
{LABELS.TABLE_TITLE_ASSET}
+
{LABELS.TABLE_TITLE_DEPOSIT_BALANCE}
+
{LABELS.TABLE_TITLE_APY}
+
{LABELS.TABLE_TITLE_ACTION}
+
+ {userDeposits.map((deposit) => ( + + ))} + + ); +}; diff --git a/src/views/dashboard/deposit/item.tsx b/src/views/dashboard/deposit/item.tsx new file mode 100644 index 0000000..9255b1a --- /dev/null +++ b/src/views/dashboard/deposit/item.tsx @@ -0,0 +1,53 @@ +import React, { useMemo } from "react"; +import { useUserCollateralBalance, useTokenName } from "../../../hooks"; +import { calculateDepositAPY, LendingReserve } from "../../../models/lending"; +import { TokenIcon } from "../../../components/TokenIcon"; +import { formatNumber, formatPct } from "../../../utils/utils"; +import { Button, Card } from "antd"; +import { Link } from "react-router-dom"; +import { TokenAccount } from "../../../models"; +import { ParsedAccount } from "../../../contexts/accounts"; +import { LABELS } from "../../../constants"; + +export const DepositItem = (props: { + reserve: ParsedAccount; + account: TokenAccount; +}) => { + const mintAddress = props.reserve.info.liquidityMint; + const name = useTokenName(mintAddress); + const { balance: collateralBalance } = useUserCollateralBalance( + props.reserve.info, + props.account.pubkey + ); + + const depositAPY = useMemo(() => calculateDepositAPY(props.reserve.info), [ + props.reserve, + ]); + + return ( + +
+ + + {name} + +
+ {formatNumber.format(collateralBalance)} {name} +
+
{formatPct.format(depositAPY)}
+
+ + + + + + +
+
+
+ ); +}; diff --git a/src/views/dashboard/index.tsx b/src/views/dashboard/index.tsx index 6f0c122..711cb47 100644 --- a/src/views/dashboard/index.tsx +++ b/src/views/dashboard/index.tsx @@ -1,9 +1,10 @@ +import { Col, Row } from "antd"; import React from "react"; import { LABELS } from "../../constants"; import { useWallet } from "../../contexts/wallet"; import { useUserDeposits, useUserObligations } from "./../../hooks"; -import { DepositItem } from "./depositItem"; -import { ObligationItem } from "./obligationItem"; +import { DashboardObligations } from "./obligation"; +import { DashboardDeposits } from "./deposit"; import "./style.less"; export const DashboardView = () => { @@ -13,44 +14,32 @@ export const DashboardView = () => { return (
- {!connected && ( -
{LABELS.DASHBOARD_INFO}
+ {!connected && ( +
+ connect your wallet + {LABELS.DASHBOARD_INFO} +
)} {connected && userDeposits.length === 0 && userObligations.length === 0 && ( -
{LABELS.NO_LOANS_NO_DEPOSITS}
+
+ connect your wallet + {LABELS.NO_LOANS_NO_DEPOSITS} +
)} - {userDeposits.length > 0 && ( -
- {LABELS.DASHBOARD_TITLE_DEPOSITS} -
-
{LABELS.TABLE_TITLE_ASSET}
-
{LABELS.TABLE_TITLE_DEPOSIT_BALANCE}
-
{LABELS.TABLE_TITLE_APY}
-
{LABELS.TABLE_TITLE_ACTION}
-
- {userDeposits.map((deposit) => ( - - ))} -
- )} - {userObligations.length > 0 && ( -
- {LABELS.DASHBOARD_TITLE_LOANS} -
-
{LABELS.TABLE_TITLE_ASSET}
-
{LABELS.TABLE_TITLE_YOUR_LOAN_BALANCE}
-
{LABELS.TABLE_TITLE_COLLATERAL_BALANCE}
-
{LABELS.TABLE_TITLE_APY}
-
{LABELS.TABLE_TITLE_LTV}
-
{LABELS.TABLE_TITLE_ACTION}
-
- {userObligations.map((item) => { - return ; - })} -
- )} + + {userDeposits.length >0 && ( + + + + )} + {userObligations.length >0 && ( + + + + )} +
); }; diff --git a/src/views/dashboard/obligation/index.tsx b/src/views/dashboard/obligation/index.tsx new file mode 100644 index 0000000..7cc3443 --- /dev/null +++ b/src/views/dashboard/obligation/index.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import { LABELS } from "../../../constants"; +import { useUserObligations } from "./../../../hooks"; +import { ObligationItem } from "./item"; + +export const DashboardObligations = () => { + const { userObligations } = useUserObligations(); + + return ( + <> + {LABELS.DASHBOARD_TITLE_LOANS} +
+
{LABELS.TABLE_TITLE_ASSET}
+
{LABELS.TABLE_TITLE_YOUR_LOAN_BALANCE}
+
{LABELS.TABLE_TITLE_COLLATERAL_BALANCE}
+
{LABELS.TABLE_TITLE_APY}
+
{LABELS.TABLE_TITLE_LTV}
+
{LABELS.TABLE_TITLE_ACTION}
+
+ {userObligations.map((item) => { + return ; + })} + + ); +}; diff --git a/src/views/dashboard/obligationItem.tsx b/src/views/dashboard/obligation/item.tsx similarity index 90% rename from src/views/dashboard/obligationItem.tsx rename to src/views/dashboard/obligation/item.tsx index cdf4938..09421d5 100644 --- a/src/views/dashboard/obligationItem.tsx +++ b/src/views/dashboard/obligation/item.tsx @@ -1,20 +1,20 @@ import React, { useMemo } from "react"; -import { EnrichedLendingObligation, useTokenName } from "../../hooks"; +import { EnrichedLendingObligation, useTokenName } from "../../../hooks"; import { calculateBorrowAPY, collateralToLiquidity, LendingReserve, -} from "../../models/lending"; -import { TokenIcon } from "../../components/TokenIcon"; +} from "../../../models/lending"; +import { TokenIcon } from "../../../components/TokenIcon"; import { wadToLamports, formatNumber, fromLamports, formatPct, -} from "../../utils/utils"; +} from "../../../utils/utils"; import { Button, Card } from "antd"; import { Link } from "react-router-dom"; -import { cache, ParsedAccount, useMint } from "../../contexts/accounts"; +import { cache, ParsedAccount, useMint } from "../../../contexts/accounts"; export const ObligationItem = (props: { obligation: EnrichedLendingObligation; diff --git a/src/views/dashboard/style.less b/src/views/dashboard/style.less index 2c1c2d0..51c4fd6 100644 --- a/src/views/dashboard/style.less +++ b/src/views/dashboard/style.less @@ -41,25 +41,23 @@ flex-direction: row; flex-wrap: wrap; flex: 1; -} -.dashboard-right { - flex: 50%; -} - -.dashboard-left { - flex: 50%; + & > :first-child { + flex: 1; + } } .dashboard-info { display: flex; + flex-direction: column; align-self: center; justify-content: center; flex: 1; -} -@media (max-width: 700px) { - .dashboard-right, .dashboard-left { - flex: 100%; + .dashboard-splash { + max-width: 400px; + width: 100%; + align-self: center; } } + diff --git a/src/views/home/index.tsx b/src/views/home/index.tsx index 85dac8d..fa9e7e1 100644 --- a/src/views/home/index.tsx +++ b/src/views/home/index.tsx @@ -3,23 +3,45 @@ import { Card, Col, Row, Statistic } from "antd"; import React, { useEffect, useState } from "react"; import { LABELS } from "../../constants"; import { cache, ParsedAccount } from "../../contexts/accounts"; +import { useConnectionConfig } from "../../contexts/connection"; import { useMarkets } from "../../contexts/market"; import { useLendingReserves } from "../../hooks"; import { reserveMarketCap } from "../../models"; -import { fromLamports, wadToLamports } from "../../utils/utils"; +import { fromLamports, getTokenName, wadToLamports } from "../../utils/utils"; import { LendingReserveItem } from "./item"; +import { BarChartStatistic } from "./../../components/BarChartStatistic"; import "./itemStyle.less"; +interface Totals { + marketSize: number; + borrowed: number; + lentOutPct: number; + items: { + marketSize: number; + borrowed: number; + name: string; + }[]; +} + export const HomeView = () => { const { reserveAccounts } = useLendingReserves(); - const [totalMarketSize, setTotalMarketSize] = useState(0); - const [totalBorrowed, setTotalBorrowed] = useState(0); const { marketEmitter, midPriceInUSD } = useMarkets(); + const { tokenMap } = useConnectionConfig(); + const [totals, setTotals] = useState({ + marketSize: 0, + borrowed: 0, + lentOutPct: 0, + items: [], + }) useEffect(() => { const refreshTotal = () => { - let totalSize = 0; - let borrowed = 0; + let newTotals: Totals = { + marketSize: 0, + borrowed: 0, + lentOutPct: 0, + items: [], + }; reserveAccounts.forEach((item) => { const marketCapLamports = reserveMarketCap(item.info); @@ -33,22 +55,28 @@ export const HomeView = () => { return; } - const marketCap = - fromLamports(marketCapLamports, liquidityMint?.info) * - midPriceInUSD(liquidityMint?.pubkey.toBase58()); - - totalSize = totalSize + marketCap; - - borrowed = - borrowed + - fromLamports( + let leaf = { + marketSize: fromLamports(marketCapLamports, liquidityMint?.info) * + midPriceInUSD(liquidityMint?.pubkey.toBase58()), + borrowed: fromLamports( wadToLamports(item.info?.borrowedLiquidityWad).toNumber(), liquidityMint.info - ); + ), + name: getTokenName(tokenMap, item.info.liquidityMint.toBase58()) + } + + newTotals.items.push(leaf); + + newTotals.marketSize = newTotals.marketSize + leaf.marketSize; + newTotals.borrowed = newTotals.borrowed + leaf.borrowed; + }); - setTotalMarketSize(totalSize); - setTotalBorrowed(borrowed); + newTotals.lentOutPct = newTotals.borrowed / newTotals.marketSize; + newTotals.lentOutPct = Number.isFinite(newTotals.lentOutPct) ? newTotals.lentOutPct : 0; + newTotals.items = newTotals.items.sort((a, b) => b.marketSize - a.marketSize) + + setTotals(newTotals); }; const dispose = marketEmitter.onMarket(() => { @@ -60,32 +88,53 @@ export const HomeView = () => { return () => { dispose(); }; - }, [marketEmitter, midPriceInUSD, setTotalMarketSize, reserveAccounts]); + }, [marketEmitter, midPriceInUSD, setTotals, reserveAccounts, tokenMap]); return (
- - + + - + + + + + + + + + item.name} + getPct={(item) => item.marketSize / totals.marketSize} + items={totals.items} /> + +
diff --git a/src/views/liquidateReserve/index.tsx b/src/views/liquidateReserve/index.tsx index 1f80791..0d6f65a 100644 --- a/src/views/liquidateReserve/index.tsx +++ b/src/views/liquidateReserve/index.tsx @@ -14,12 +14,12 @@ export const LiquidateReserveView = () => { const { id } = useParams<{ id: string }>(); const obligation = useEnrichedLendingObligation(id); - const reserve = useLendingReserve(obligation?.info.borrowReserve); - const collateralReserve = useLendingReserve( + const repayReserve = useLendingReserve(obligation?.info.borrowReserve); + const withdrawReserve = useLendingReserve( obligation?.info.collateralReserve ); - if (!obligation || !reserve) { + if (!obligation || !repayReserve) { return null; } @@ -29,12 +29,12 @@ export const LiquidateReserveView = () => {
diff --git a/yarn.lock b/yarn.lock index 5709ed7..4254e89 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,7 +42,7 @@ resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.1.0.tgz#480b025f4b20ef7fe8f47d4a4846e4fee84ea06c" integrity sha512-Fi03PfuUqRs76aI3UWYpP864lkrfPo0hluwGqh7NJdLhvH4iRDc3jbJqZIvRDLHKbXrvAfPPV3+zjUccfFvWOQ== -"@ant-design/icons@^4.0.0": +"@ant-design/icons@^4.0.0", "@ant-design/icons@^4.3.0": version "4.3.0" resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-4.3.0.tgz#420e0cd527486c0fe57f81310d681950fc4cfacf" integrity sha512-UoIbw4oz/L/msbkgqs2nls2KP7XNKScOxVR54wRrWwnXOzJaGNwwSdYjHQz+5ETf8C53YPpzMOnRX99LFCdeIQ== @@ -66,14 +66,14 @@ insert-css "^2.0.0" rc-util "^5.0.1" -"@ant-design/pro-layout@^6.5.14": - version "6.5.15" - resolved "https://registry.yarnpkg.com/@ant-design/pro-layout/-/pro-layout-6.5.15.tgz#a5b8fb414ca51deebc8c4214b09699cfc30b60a7" - integrity sha512-AN9UQGbdK/4RwF0Uf5HkwdXsCRRzC1FeQv8jBKlzcsHEm/FGa9KslIDcjDzOR7q2P9NiysaBsWIGPIM/aRox5A== +"@ant-design/pro-layout@^6.7.0": + version "6.7.0" + resolved "https://registry.yarnpkg.com/@ant-design/pro-layout/-/pro-layout-6.7.0.tgz#eba8d51bdf588c9a7ee58837a134f0f2bd8c14b3" + integrity sha512-IGTtbsiTuKLwyHj4DEq6CfwFdh0YOnz/jGnikDQFMPmUtK/yeFa/rM2M4xmtVycPTzOZAx7A+UARw5VWLNy9cg== dependencies: "@ant-design/icons" "^4.0.0" - "@ant-design/pro-provider" "1.2.1" - "@ant-design/pro-utils" "1.2.0" + "@ant-design/pro-provider" "1.2.4" + "@ant-design/pro-utils" "1.5.1" "@umijs/route-utils" "^1.0.33" classnames "^2.2.6" history "^4.10.1" @@ -82,6 +82,7 @@ path-to-regexp "2.4.0" qs "^6.9.0" rc-resize-observer "^0.2.1" + rc-util "^5.0.6" react-copy-to-clipboard "^5.0.1" react-responsive "^8.0.1" react-router-dom "5.1.2" @@ -90,20 +91,23 @@ use-media-antd-query "^1.0.3" warning "^4.0.3" -"@ant-design/pro-provider@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@ant-design/pro-provider/-/pro-provider-1.2.1.tgz#1dadd1e196dac363e002390aeb84a1ce0ed67118" - integrity sha512-k2kT7zb1QhzJQvCuhfKXUwJJV6KsvyNtxbguDA3zoiK57EEAMRyxuiLMeNk6ejeY/Kak3l9yx2YiANuRRzU6Vg== +"@ant-design/pro-provider@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@ant-design/pro-provider/-/pro-provider-1.2.4.tgz#de1dc8fdf9c3e3156e0540a4d5db61c4e6c4e2c1" + integrity sha512-tYk97VmhctXY/BAv6K+qVRBddHxmWkSf3QbU6cRhmnb0ofPV26wEX8oWa26MBqlS4QPry0+L4VO8n4iLQ8HaUw== dependencies: rc-util "^5.0.1" -"@ant-design/pro-utils@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ant-design/pro-utils/-/pro-utils-1.2.0.tgz#2bf2157558095b18224bba4ba0a18081f03a1689" - integrity sha512-k5Mo1Ma8cTB2aMSXI6VA5YwNO4BxGmUIugUrQJVRcu3OupTle1bYJf7tePUpPyN++Oe5AbSHwXl+c0CtfF01hA== +"@ant-design/pro-utils@1.5.1": + version "1.5.1" + resolved "https://registry.yarnpkg.com/@ant-design/pro-utils/-/pro-utils-1.5.1.tgz#e3cc1ef352cd804d562fcf1049e8d490602b48f4" + integrity sha512-dM2Q9ex8d28+RuaoFczkCY50KHG5666RqryzxA1IeMNVNTsU8iqflPl3v94+yiYonDTyHECIm4ZKqUlz2H4c/g== dependencies: - "@ant-design/pro-provider" "1.2.1" + "@ant-design/icons" "^4.3.0" + "@ant-design/pro-provider" "1.2.4" + classnames "^2.2.6" fast-deep-equal "^3.1.3" + moment "^2.27.0" rc-util "^5.0.6" "@ant-design/react-slick@~0.27.0": @@ -8042,7 +8046,7 @@ mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: dependencies: minimist "^1.2.5" -moment@^2.24.0, moment@^2.25.3: +moment@^2.24.0, moment@^2.25.3, moment@^2.27.0: version "2.29.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==