feat: hookup liquidate

This commit is contained in:
bartosz-lipinski 2020-12-19 21:33:49 -06:00
parent 552b5c4527
commit f24645810a
17 changed files with 2753 additions and 146 deletions

2222
public/splash.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 216 KiB

View File

@ -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;

View File

@ -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
)

View File

@ -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";

141
src/actions/liquidate.tsx Normal file
View File

@ -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<LendingObligation>,
repayReserve: ParsedAccount<LendingReserve>,
withdrawReserve: ParsedAccount<LendingReserve>,
) => {
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}`,
});
};

View File

@ -0,0 +1,40 @@
import { Statistic } from "antd";
import React, { } from "react";
export const BarChartStatistic = <T, >(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 (
<Statistic
title={props.title}
valueRender={() =>
<div style={{ width: '100%', height: 40, display: 'flex', backgroundColor: 'lightgrey',
fontSize: 12,
lineHeight: '40px', }}>
{props.items.map((item, i) =>
<div key={props.name(item)}
title={props.name(item)}
style={{
width: `${100 * props.getPct(item)}%` ,
backgroundColor: colors[i % props.items.length] }} >
{props.name(item)}
</div>)}
</div>}
>
</Statistic>
);
};

View File

@ -42,7 +42,7 @@ export const AppLayout = (props: any) => {
</div>
<BasicLayout
title={LABELS.APP_TITLE}
footerRender={() => <div className="footer">{LABELS.FOOTER}</div>}
footerRender={() => <div className="footer" title={LABELS.FOOTER}>{LABELS.FOOTER}</div>}
navTheme={theme}
headerTheme={theme}
theme={theme}

View File

@ -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<LendingReserve>;
collateralReserve?: ParsedAccount<LendingReserve>;
repayReserve: ParsedAccount<LendingReserve>;
withdrawReserve?: ParsedAccount<LendingReserve>;
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 (
<Card className={props.className} bodyStyle={bodyStyle}>
<div
style={{
display: "flex",
flexDirection: "column",
justifyContent: "space-around",
}}
>
<div className="liquidate-input-title">{LABELS.SELECT_COLLATERAL}</div>
<CollateralSelector
reserve={reserve.info}
collateralReserve={collateralReserve?.pubkey.toBase58()}
disabled={true}
/>
<Button type="primary" onClick={onLiquidate} loading={pendingTx}>
{LABELS.LIQUIDATE_ACTION}
</Button>
<BackButton />
</div>
{showConfirmation ? (
<ActionConfirmation onClose={() => setShowConfirmation(false)} />
) : (
<div
style={{
display: "flex",
flexDirection: "column",
justifyContent: "space-around",
}}
>
<div className="liquidate-input-title">{LABELS.SELECT_COLLATERAL}</div>
<CollateralSelector
reserve={repayReserve.info}
collateralReserve={withdrawReserve?.pubkey.toBase58()}
disabled={true}
/>
<Button type="primary"
onClick={onLiquidate}
disabled={fromAccounts.length === 0}
loading={pendingTx}>
{LABELS.LIQUIDATE_ACTION}
</Button>
<BackButton />
</div>)}
</Card>
);
};

View File

@ -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 (<>
<span>{LABELS.DASHBOARD_TITLE_DEPOSITS}</span>
<div className="dashboard-item dashboard-header">
<div>{LABELS.TABLE_TITLE_ASSET}</div>
<div>{LABELS.TABLE_TITLE_DEPOSIT_BALANCE}</div>
<div>{LABELS.TABLE_TITLE_APY}</div>
<div>{LABELS.TABLE_TITLE_ACTION}</div>
</div>
{userDeposits.map((deposit) => (
<DepositItem reserve={deposit.reserve} account={deposit.account} />
))}
</>
);
};

View File

@ -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<LendingReserve>;
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 (
<Card>
<div className="dashboard-item">
<span style={{ display: "flex" }}>
<TokenIcon mintAddress={mintAddress} />
{name}
</span>
<div>
{formatNumber.format(collateralBalance)} {name}
</div>
<div>{formatPct.format(depositAPY)}</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<Link to={`/deposit/${props.reserve.pubkey.toBase58()}`}>
<Button>
<span>{LABELS.DEPOSIT_ACTION}</span>
</Button>
</Link>
<Link to={`/withdraw/${props.reserve.pubkey.toBase58()}`}>
<Button>
<span>{LABELS.WITHDRAW_ACTION}</span>
</Button>
</Link>
</div>
</div>
</Card>
);
};

View File

@ -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 (
<div className="dashboard-container">
{!connected && (
<div className="dashboard-info">{LABELS.DASHBOARD_INFO}</div>
{!connected && (
<div className="dashboard-info">
<img src="splash.svg" alt="connect your wallet" className="dashboard-splash"/>
{LABELS.DASHBOARD_INFO}
</div>
)}
{connected &&
userDeposits.length === 0 &&
userObligations.length === 0 && (
<div className="dashboard-info">{LABELS.NO_LOANS_NO_DEPOSITS}</div>
<div className="dashboard-info">
<img src="splash.svg" alt="connect your wallet" className="dashboard-splash"/>
{LABELS.NO_LOANS_NO_DEPOSITS}
</div>
)}
{userDeposits.length > 0 && (
<div className="dashboard-left">
<span>{LABELS.DASHBOARD_TITLE_DEPOSITS}</span>
<div className="dashboard-item dashboard-header">
<div>{LABELS.TABLE_TITLE_ASSET}</div>
<div>{LABELS.TABLE_TITLE_DEPOSIT_BALANCE}</div>
<div>{LABELS.TABLE_TITLE_APY}</div>
<div>{LABELS.TABLE_TITLE_ACTION}</div>
</div>
{userDeposits.map((deposit) => (
<DepositItem reserve={deposit.reserve} account={deposit.account} />
))}
</div>
)}
{userObligations.length > 0 && (
<div className="dashboard-right">
<span>{LABELS.DASHBOARD_TITLE_LOANS}</span>
<div className="dashboard-item dashboard-header">
<div>{LABELS.TABLE_TITLE_ASSET}</div>
<div>{LABELS.TABLE_TITLE_YOUR_LOAN_BALANCE}</div>
<div>{LABELS.TABLE_TITLE_COLLATERAL_BALANCE}</div>
<div>{LABELS.TABLE_TITLE_APY}</div>
<div>{LABELS.TABLE_TITLE_LTV}</div>
<div>{LABELS.TABLE_TITLE_ACTION}</div>
</div>
{userObligations.map((item) => {
return <ObligationItem obligation={item.obligation} />;
})}
</div>
)}
<Row gutter={[16, { xs: 8, sm: 16, md: 16, lg: 16 }]} >
{userDeposits.length >0 && (
<Col md={24} xl={12} span={24}>
<DashboardDeposits />
</Col>
)}
{userObligations.length >0 && (
<Col md={24} xl={12} span={24}>
<DashboardObligations />
</Col>
)}
</Row>
</div>
);
};

View File

@ -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 (
<>
<span>{LABELS.DASHBOARD_TITLE_LOANS}</span>
<div className="dashboard-item dashboard-header">
<div>{LABELS.TABLE_TITLE_ASSET}</div>
<div>{LABELS.TABLE_TITLE_YOUR_LOAN_BALANCE}</div>
<div>{LABELS.TABLE_TITLE_COLLATERAL_BALANCE}</div>
<div>{LABELS.TABLE_TITLE_APY}</div>
<div>{LABELS.TABLE_TITLE_LTV}</div>
<div>{LABELS.TABLE_TITLE_ACTION}</div>
</div>
{userObligations.map((item) => {
return <ObligationItem obligation={item.obligation} />;
})}
</>
);
};

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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<Totals>({
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 (
<div className="flexColumn">
<Row gutter={16} className="home-info-row">
<Col span={12}>
<Row
gutter={[16, { xs: 8, sm: 16, md: 16, lg: 16 }]}
className="home-info-row" >
<Col xs={24} xl={5}>
<Card>
<Statistic
title="Current market size"
value={totalMarketSize}
value={totals.marketSize}
precision={2}
valueStyle={{ color: "#3f8600" }}
prefix="$"
/>
</Card>
</Col>
<Col span={12}>
<Col xs={24} xl={5}>
<Card>
<Statistic
title="Total borrowed"
value={totalBorrowed}
value={totals.borrowed}
precision={2}
prefix="$"
/>
</Card>
</Col>
<Col xs={24} xl={5}>
<Card>
<Statistic
title="% Lent out"
value={totals.lentOutPct * 100}
precision={2}
suffix="%"
/>
</Card>
</Col>
<Col xs={24} xl={9}>
<Card>
<BarChartStatistic
title="Market composition"
name={(item) => item.name}
getPct={(item) => item.marketSize / totals.marketSize}
items={totals.items} />
</Card>
</Col>
</Row>
<div className="home-item home-header">

View File

@ -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 = () => {
<LiquidateInput
className="liquidate-reserve-item liquidate-reserve-item-left"
obligation={obligation}
collateralReserve={collateralReserve}
reserve={reserve}
withdrawReserve={withdrawReserve}
repayReserve={repayReserve}
/>
<SideReserveOverview
className="liquidate-reserve-item liquidate-reserve-item-right"
reserve={reserve}
reserve={repayReserve}
mode={SideReserveOverviewMode.Deposit}
/>
</div>

View File

@ -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==