Skip to content
Merged
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
2 changes: 2 additions & 0 deletions apps/lite/src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Link, Outlet, useLocation, useNavigate, useParams } from "react-router"
import { Toaster } from "sonner";
import { useChains } from "wagmi";

import { DeprecationModal } from "@/components/deprecation-modal";
import { Footer } from "@/components/footer";
import { Header } from "@/components/header";
import { MorphoMenu } from "@/components/morpho-menu";
Expand Down Expand Up @@ -111,6 +112,7 @@ export default function Page() {
</div>
</Header>
<WelcomeModal />
<DeprecationModal chainId={chain?.id} />
<Outlet context={{ chain }} />
<Footer />
</div>
Expand Down
9 changes: 5 additions & 4 deletions apps/lite/src/components/borrow-sheet-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { useCallback, useMemo, useState } from "react";
import { Address, erc20Abi, parseUnits } from "viem";
import { useAccount, useChainId, useReadContract, useReadContracts } from "wagmi";

import { RISKS_DOCUMENTATION, TRANSACTION_DATA_SUFFIX } from "@/lib/constants";
import { isReduceOnly, RISKS_DOCUMENTATION, TRANSACTION_DATA_SUFFIX } from "@/lib/constants";

enum Actions {
SupplyCollateral = "Supply",
Expand Down Expand Up @@ -71,8 +71,9 @@ export function BorrowSheetContent({
}) {
const chainId = useChainId();
const { address: userAddress } = useAccount();
const reduceOnly = isReduceOnly(chainId);

const [selectedTab, setSelectedTab] = useState(Actions.SupplyCollateral);
const [selectedTab, setSelectedTab] = useState(reduceOnly ? Actions.WithdrawCollateral : Actions.SupplyCollateral);
const [textInputValue, setTextInputValue] = useState("");

const morpho = getContractDeploymentInfo(chainId, "Morpho").address;
Expand Down Expand Up @@ -328,13 +329,13 @@ export function BorrowSheetContent({
}}
>
<TabsList className="grid w-full grid-cols-4 gap-1 bg-transparent p-0">
<TabsTrigger className={STYLE_TAB} value={Actions.SupplyCollateral}>
<TabsTrigger className={STYLE_TAB} value={Actions.SupplyCollateral} disabled={reduceOnly}>
{Actions.SupplyCollateral}
</TabsTrigger>
<TabsTrigger className={STYLE_TAB} value={Actions.WithdrawCollateral}>
{Actions.WithdrawCollateral}
</TabsTrigger>
<TabsTrigger className={STYLE_TAB} value={Actions.Borrow}>
<TabsTrigger className={STYLE_TAB} value={Actions.Borrow} disabled={reduceOnly}>
{Actions.Borrow}
</TabsTrigger>
<TabsTrigger className={STYLE_TAB} value={Actions.Repay}>
Expand Down
81 changes: 81 additions & 0 deletions apps/lite/src/components/deprecation-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { SafeLink } from "@morpho-org/uikit/components/safe-link";
import {
AlertDialog,
AlertDialogAction,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@morpho-org/uikit/components/shadcn/alert-dialog";
import { useEffect, useState } from "react";

import { CHAIN_DEPRECATION_INFO } from "@/lib/constants";

export function DeprecationModal({ chainId }: { chainId: number | undefined }) {
const deprecationInfo = chainId !== undefined ? CHAIN_DEPRECATION_INFO[chainId] : undefined;
const [open, setOpen] = useState(true);

// Reset to open when chainId changes
useEffect(() => {
setOpen(true);
}, [chainId]);

if (!deprecationInfo) {
return null;
}

return (
<AlertDialog key={chainId} open={open} onOpenChange={setOpen}>
<AlertDialogContent className="rounded-2xl">
<AlertDialogHeader>
<AlertDialogTitle className="mb-3 text-2xl font-light">
{deprecationInfo.chain.name} Deprecation Notice
</AlertDialogTitle>
<AlertDialogDescription asChild>
<div className="bg-secondary text-secondary-foreground rounded-lg p-4 font-light">
<p>
Lite is now <strong className="font-medium">reduce-only</strong> on {deprecationInfo.chain.name}. You
can still repay, withdraw, and close positions, but you can&apos;t open new ones.
</p>
<p className="mt-4">
<strong className="font-medium">
On {deprecationInfo.cutoffDate}, {deprecationInfo.chain.name} will be removed.
</strong>{" "}
After that, this chain won&apos;t be available in the Lite app.
</p>
<p className="mt-4 font-medium">What to do next:</p>
<ul className="mt-2 list-disc pl-5">
<li>
Use{" "}
<SafeLink className="underline" href={deprecationInfo.ecosystemBuilderUrl}>
{deprecationInfo.ecosystemBuilder}
</SafeLink>{" "}
to keep using {deprecationInfo.chain.name} with full functionality. Your positions will show there
automatically.
</li>
<li className="mt-1">
Need to exit later? The{" "}
<SafeLink className="underline" href="https://fallback.morpho.org">
fallback app
</SafeLink>{" "}
will always let you reduce positions.
</li>
</ul>
</div>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<SafeLink
href="https://help.morpho.org/en/articles/13560956-morpho-lite-app-deprecation"
target="_blank"
className="bg-morpho-gray hover:bg-secondary inline-flex h-9 items-center justify-center rounded-full px-4 py-2 text-sm font-medium"
>
Learn More
</SafeLink>
<AlertDialogAction className="bg-morpho-error rounded-full hover:bg-red-500">I Understand</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
9 changes: 6 additions & 3 deletions apps/lite/src/components/earn-sheet-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { useState } from "react";
import { Address, erc20Abi, erc4626Abi, parseUnits } from "viem";
import { useAccount, useBytecode, useReadContract, useReadContracts } from "wagmi";

import { RISKS_DOCUMENTATION, TRANSACTION_DATA_SUFFIX } from "@/lib/constants";
import { isReduceOnly, RISKS_DOCUMENTATION, TRANSACTION_DATA_SUFFIX } from "@/lib/constants";

enum Actions {
Deposit = "Deposit",
Expand All @@ -31,17 +31,20 @@ const STYLE_INPUT_WRAPPER =
const STYLE_INPUT_HEADER = "text-secondary-foreground flex items-center justify-between text-xs font-light";

export function EarnSheetContent({
chainId,
vaultAddress,
isDeadDepositStateValid,
asset,
}: {
chainId: number | undefined;
vaultAddress: Address;
isDeadDepositStateValid: boolean;
asset: Token;
}) {
const { address: userAddress } = useAccount();
const reduceOnly = isReduceOnly(chainId);

const [selectedTab, setSelectedTab] = useState(Actions.Deposit);
const [selectedTab, setSelectedTab] = useState(reduceOnly ? Actions.Withdraw : Actions.Deposit);
const [textInputValue, setTextInputValue] = useState("");

// TODO: TEMPORARY
Expand Down Expand Up @@ -142,7 +145,7 @@ export function EarnSheetContent({
}}
>
<TabsList className="grid w-full grid-cols-2 gap-1 bg-transparent p-0">
<TabsTrigger className={STYLE_TAB} value={Actions.Deposit}>
<TabsTrigger className={STYLE_TAB} value={Actions.Deposit} disabled={reduceOnly}>
{Actions.Deposit}
</TabsTrigger>
<TabsTrigger className={STYLE_TAB} value={Actions.Withdraw}>
Expand Down
1 change: 1 addition & 0 deletions apps/lite/src/components/earn-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ export function EarnTable({
</TableRow>
</SheetTrigger>
<EarnSheetContent
chainId={chain?.id}
vaultAddress={row.vault.address}
isDeadDepositStateValid={row.isDeadDepositStateValid}
asset={row.asset}
Expand Down
37 changes: 32 additions & 5 deletions apps/lite/src/components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
import { useKeyedState } from "@morpho-org/uikit/hooks/use-keyed-state";
import { useLocalStorage } from "@morpho-org/uikit/hooks/use-local-storage";
import { cn } from "@morpho-org/uikit/lib/utils";
import { XIcon } from "lucide-react";

import { BANNERS } from "@/lib/constants";
import { APP_DEPRECATION_BANNER, BANNERS } from "@/lib/constants";

function Banner(chainId: number | undefined) {
function AppDeprecationBanner() {
const [shouldShowBanner, setShouldShowBanner] = useLocalStorage("shouldShowAppDeprecationBanner", true);

if (!APP_DEPRECATION_BANNER || !shouldShowBanner) {
return { placeholder: undefined, banner: undefined };
}

return {
placeholder: <div className="h-10 min-h-min"></div>,
banner: (
<aside
className={cn(
"pointer-events-auto flex h-10 min-h-min items-center px-1 text-sm font-light italic",
APP_DEPRECATION_BANNER.color,
)}
>
{APP_DEPRECATION_BANNER.text}
<XIcon className="hover:bg-accent mx-2 h-6 w-6 rounded-sm p-1" onClick={() => setShouldShowBanner(false)} />
</aside>
),
};
}

function ChainBanner(chainId: number | undefined) {
const [shouldShowBanner, setShouldShowBanner] = useKeyedState(true, chainId, { persist: true });

if (chainId === undefined || !BANNERS[chainId] || !shouldShowBanner) {
Expand All @@ -29,12 +53,15 @@ function Banner(chainId: number | undefined) {
}

export function Header({ className, children, chainId, ...props }: React.ComponentProps<"div"> & { chainId?: number }) {
const { placeholder, banner } = Banner(chainId);
const { placeholder: deprecationPlaceholder, banner: deprecationBanner } = AppDeprecationBanner();
const { placeholder: chainPlaceholder, banner: chainBanner } = ChainBanner(chainId);
return (
<>
{placeholder}
{deprecationPlaceholder}
{chainPlaceholder}
<div className="pointer-events-none fixed top-0 z-50 flex h-screen w-screen flex-col">
{banner}
{deprecationBanner}
{chainBanner}
<header className={cn("bg-primary pointer-events-auto h-16", className)} {...props}>
{children}
</header>
Expand Down
56 changes: 54 additions & 2 deletions apps/lite/src/lib/constants.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,59 @@
import { SafeLink } from "@morpho-org/uikit/components/safe-link";
import { type Deployments } from "@morpho-org/uikit/lib/deployments";
import { ReactNode } from "react";
import { hemi, optimism, plumeMainnet, polygon, sei, worldchain } from "wagmi/chains";
import { type Chain, hemi, optimism, plumeMainnet, polygon, sei, worldchain } from "wagmi/chains";

/**
* App-wide deprecation banner configuration.
* Set to undefined to disable the banner.
*/
export const APP_DEPRECATION_BANNER: { color: string; text: ReactNode } | undefined = {
color: "bg-amber-600",
text: (
<span className="grow py-2 text-center">
Morpho Lite will be gradually phased out in the coming months; learn more{" "}
<SafeLink
href="https://help.morpho.org/en/articles/13560956-morpho-lite-app-deprecation"
target="_blank"
className="underline"
>
here
</SafeLink>
.
</span>
),
};

/**
* Chain-specific deprecation modal configuration.
* Only chains listed here will show the deprecation modal.
*/
export const CHAIN_DEPRECATION_INFO: Partial<
Record<keyof Deployments, { chain: Chain; cutoffDate: string; ecosystemBuilder: string; ecosystemBuilderUrl: string }>
> = {
[worldchain.id]: {
chain: worldchain,
cutoffDate: "February 14, 2026",
ecosystemBuilder: "Oku",
ecosystemBuilderUrl: "https://oku.trade/morpho/vaults?inputChain=worldchain",
},
[plumeMainnet.id]: {
chain: plumeMainnet,
cutoffDate: "February 14, 2026",
ecosystemBuilder: "Mystic",
ecosystemBuilderUrl: "https://app.mysticfinance.xyz",
},
[sei.id]: {
chain: sei,
cutoffDate: "February 14, 2026",
ecosystemBuilder: "Feather",
ecosystemBuilderUrl: "https://app.feather.zone/portfolio",
},
};

export function isReduceOnly(chainId: number | undefined) {
return chainId !== undefined && CHAIN_DEPRECATION_INFO[chainId] !== undefined;
}

export const APP_DETAILS = {
// NOTE: Should always match the title in `index.html` (won't break anything, but should be correct)
Expand Down Expand Up @@ -91,7 +143,7 @@ export const BANNERS: Record<keyof Deployments, { color: string; text: ReactNode
<span className="grow py-2 text-center">
Claim rewards and access enhanced features on the external{" "}
<SafeLink className="underline" href="https://oku.trade/morpho/vaults?inputChain=worldchain">
Oku Trade
Oku
</SafeLink>{" "}
interface.
</span>
Expand Down
19 changes: 0 additions & 19 deletions apps/lite/src/lib/wagmi-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,6 @@ function createFallbackTransport(rpcs: ({ url: string } & HttpTransportConfig)[]
);
}

function createPonderHttp(chainId: number) {
return [
{
url: `https://v1-indexer.marble.live/rpc/${chainId}`,
batch: false,
methods: { include: ["eth_getLogs"] },
},
];
}

function createPrivateProxyHttp(chainId: number): ({ url: string } & HttpTransportConfig)[] {
const subdomain = import.meta.env.DEV ? "rpc-dev" : "rpc";
const url = `https://${subdomain}.morpho.dev/cache/evm/${chainId}?secret=${import.meta.env.VITE_ERPC_API_KEY}`;
Expand Down Expand Up @@ -102,47 +92,40 @@ const chains = [
const transports: { [K in (typeof chains)[number]["id"]]: Transport } & { [k: number]: Transport } = {
// full support
[mainnet.id]: createFallbackTransport([
...createPonderHttp(mainnet.id),
...createPrivateProxyHttp(mainnet.id),
{ url: "https://rpc.mevblocker.io", batch: { batchSize: 10 } },
{ url: "https://rpc.ankr.com/eth", batch: { batchSize: 10 } },
{ url: "https://eth.drpc.org", batch: false },
{ url: "https://eth.merkle.io", batch: false },
]),
[base.id]: createFallbackTransport([
...createPonderHttp(base.id),
...createPrivateProxyHttp(base.id),
{ url: "https://base.gateway.tenderly.co", batch: { batchSize: 10 } },
{ url: "https://base.drpc.org", batch: false },
{ url: "https://mainnet.base.org", batch: { batchSize: 10 } },
{ url: "https://base.lava.build", batch: false },
]),
[polygon.id]: createFallbackTransport([
...createPonderHttp(polygon.id),
...createPrivateProxyHttp(polygon.id),
{ url: "https://polygon.gateway.tenderly.co", batch: { batchSize: 10 } },
{ url: "https://polygon.drpc.org", batch: false },
]),
[unichain.id]: createFallbackTransport([
...createPonderHttp(unichain.id),
...createPrivateProxyHttp(unichain.id),
{ url: "https://unichain.gateway.tenderly.co", batch: { batchSize: 10 } },
{ url: "https://unichain.drpc.org", batch: false },
]),
[customChains.katana.id]: createFallbackTransport([
...createPonderHttp(customChains.katana.id),
...createPrivateProxyHttp(customChains.katana.id),
...customChains.katana.rpcUrls.default.http.map((url) => ({ url, batch: false })),
]),
[arbitrum.id]: createFallbackTransport([
...createPonderHttp(arbitrum.id),
...createPrivateProxyHttp(arbitrum.id),
{ url: "https://arbitrum.gateway.tenderly.co", batch: { batchSize: 10 } },
{ url: "https://rpc.ankr.com/arbitrum", batch: { batchSize: 10 } },
{ url: "https://arbitrum.drpc.org", batch: false },
]),
[customChains.hyperevm.id]: createFallbackTransport([
...createPonderHttp(customChains.hyperevm.id),
...createPrivateProxyHttp(customChains.hyperevm.id),
{ url: "https://rpc.hyperlend.finance/archive", batch: false },
]),
Expand Down Expand Up @@ -202,7 +185,6 @@ const transports: { [K in (typeof chains)[number]["id"]]: Transport } & { [k: nu
{ url: "https://scroll.drpc.org", batch: false },
]),
[sei.id]: createFallbackTransport([
...createPonderHttp(sei.id),
...createPrivateProxyHttp(sei.id),
{ url: "https://sei-public.nodies.app", batch: false, key: "sei-nodies-maxNum-2000" },
{ url: "https://sei.therpc.io", batch: false, key: "sei-therpc-maxNum-2000" },
Expand All @@ -221,7 +203,6 @@ const transports: { [K in (typeof chains)[number]["id"]]: Transport } & { [k: nu
{ url: "https://sonic.drpc.org", batch: false },
]),
[customChains.tac.id]: createFallbackTransport([
...createPonderHttp(customChains.tac.id),
...createPrivateProxyHttp(customChains.tac.id),
{ url: "https://rpc.tac.build/", batch: false },
{ url: "https://tac.therpc.io", batch: false },
Expand Down
Loading
Loading