diff --git a/src/app/(routes)/across-plus/_components/get-started-section.tsx b/src/app/(routes)/across-plus/_components/get-started-section.tsx
index cc7f67a..b58d637 100644
--- a/src/app/(routes)/across-plus/_components/get-started-section.tsx
+++ b/src/app/(routes)/across-plus/_components/get-started-section.tsx
@@ -1,38 +1,13 @@
import Image from "next/image";
-import { ArrowRightIcon } from "@/app/_components/icons";
-import { Text } from "@/app/_components/text";
+import { GetStartedSection } from "@/app/_components/get-started-section";
import plusGetStartedImage from "@/app/_assets/plus-get-started.png";
-import { INFORMATION_LINKS } from "@/app/_constants";
-export function GetStartedSection() {
+export function PlusGetStartedSection() {
return (
-
-
-
- Ready to get started?
-
-
-
+
}
+ />
);
}
diff --git a/src/app/(routes)/across-plus/page.tsx b/src/app/(routes)/across-plus/page.tsx
index a7e885b..3e2e7c8 100644
--- a/src/app/(routes)/across-plus/page.tsx
+++ b/src/app/(routes)/across-plus/page.tsx
@@ -3,8 +3,8 @@ import { Metadata } from "next";
import { HeroSection } from "./_components/hero-section";
import { FeaturesSection } from "./_components/features-section";
import { UseCasesSection } from "./_components/use-cases-section";
-import { SupportedChainsSection } from "./_components/supported-chains-section";
-import { GetStartedSection } from "./_components/get-started-section";
+import { SupportedChainsSection } from "@/app/_components/supported-chains-section";
+import { PlusGetStartedSection } from "./_components/get-started-section";
export const metadata: Metadata = {
title: "Across Plus",
@@ -17,8 +17,8 @@ export default function PlusLanding() {
-
-
+
+
);
}
diff --git a/src/app/(routes)/across-settlement/_components/features-section.tsx b/src/app/(routes)/across-settlement/_components/features-section.tsx
new file mode 100644
index 0000000..6d12593
--- /dev/null
+++ b/src/app/(routes)/across-settlement/_components/features-section.tsx
@@ -0,0 +1,65 @@
+import {
+ BlocksConnectedIcon,
+ ChecklistIcon,
+ CheckmarkIcon,
+ CrossChainIcon,
+} from "@/app/_components/icons";
+import { Text } from "@/app/_components/text";
+import settlement2Image from "@/app/_assets/settlement-2.png";
+import Image from "next/image";
+
+const features = [
+ {
+ Icon:
,
+ title: "Cross-Chain Intents Settlement",
+ body: "Intents are cross-chain limit orders submitted to an RFQ system and fulfilled by relayers with their own capital. Settlement verifies fulfillment and repays relayers. Across’ maximally efficient settlement system reduces cost to relayers, and ultimately, users.",
+ },
+ {
+ Icon:
,
+ title: "Modular by design",
+ body: "Across Settlement can accept any intents-based order flow following a standard structure. It seamlessly enables any DEX or application with RFQ order flow to offer best-execution cross-chain swaps from the most competitive network of professional market markets.",
+ },
+ {
+ Icon:
,
+ title: "aggregated and optimistic verification",
+ body: "Across verifies fulfillment optimistically. This enables aggregated, off-chain verification and repayment over a 1-2 hour period, amortizing this cost over thousands of orders, resulting in an order of magnitude gas savings vs. per-fill repayment.",
+ },
+ {
+ Icon:
,
+ title: "Seamless cross-chain management",
+ body: "Repayment is made on the relayers’ chain of choice, reducing overhead and complexity of managing cross-chain positions. Lower costs for relayers resulting in lower costs for users.",
+ },
+];
+
+export function FeaturesSection() {
+ return (
+
+
+
+
+ industry-leading performance
+
+
+ Superior settlement
+
+ Best Execution
+
+
+
+ {features.map((feature) => (
+
+ {feature.Icon}
+
+ {feature.title}
+
+ {feature.body}
+
+ ))}
+
+
+ );
+}
diff --git a/src/app/(routes)/across-settlement/_components/get-started-section.tsx b/src/app/(routes)/across-settlement/_components/get-started-section.tsx
new file mode 100644
index 0000000..9e1c3c1
--- /dev/null
+++ b/src/app/(routes)/across-settlement/_components/get-started-section.tsx
@@ -0,0 +1,19 @@
+import Image from "next/image";
+
+import { GetStartedSection } from "@/app/_components/get-started-section";
+import settlementLayerImage from "@/app/_assets/settlement-layer.png";
+
+export function SettlementGetStartedSection() {
+ return (
+
+ }
+ />
+ );
+}
diff --git a/src/app/(routes)/across-settlement/_components/hero-section.tsx b/src/app/(routes)/across-settlement/_components/hero-section.tsx
new file mode 100644
index 0000000..bb0c8f6
--- /dev/null
+++ b/src/app/(routes)/across-settlement/_components/hero-section.tsx
@@ -0,0 +1,53 @@
+import Image from "next/image";
+
+import { Text } from "@/app/_components/text";
+import { ArrowRightIcon } from "@/app/_components/icons/arrow-right";
+import settlementHeroImage from "@/app/_assets/settlement-hero.png";
+import { INFORMATION_LINKS } from "@/app/_constants";
+
+export function HeroSection() {
+ return (
+
+
+
+
+
+
+
+ Cross-Chain{" "}
+ Intents
+ Settlement{" "}
+ Layer
+
+
+
+ Efficiently transform RFQ order flow into cross-chain swaps with
+ Across' intents settlement system.
+
+
+
+ go to docs
+
+
+
+
+
+ );
+}
diff --git a/src/app/(routes)/across-settlement/_components/stats-section.tsx b/src/app/(routes)/across-settlement/_components/stats-section.tsx
new file mode 100644
index 0000000..01a0f45
--- /dev/null
+++ b/src/app/(routes)/across-settlement/_components/stats-section.tsx
@@ -0,0 +1,20 @@
+import { StatsRow } from "@/app/_components/stats-row";
+
+const statBoxOverrides = {
+ className: "group-hover:border-purple-100",
+ titleClassName: "text-purple-100",
+ dividerClassName: "group-hover:bg-purple-100/[.5]",
+};
+
+export async function StatsSection() {
+ return (
+
+ );
+}
diff --git a/src/app/(routes)/across-settlement/page.tsx b/src/app/(routes)/across-settlement/page.tsx
index efe1b7c..109a03f 100644
--- a/src/app/(routes)/across-settlement/page.tsx
+++ b/src/app/(routes)/across-settlement/page.tsx
@@ -1,5 +1,11 @@
import { Metadata } from "next";
+import { HeroSection } from "./_components/hero-section";
+import { StatsSection } from "./_components/stats-section";
+import { FeaturesSection } from "./_components/features-section";
+import { SupportedChainsSection } from "@/app/_components/supported-chains-section";
+import { SettlementGetStartedSection } from "./_components/get-started-section";
+
export const metadata: Metadata = {
title: "Across Settlement",
description: "Interoperability powered by Intents.",
@@ -7,8 +13,12 @@ export const metadata: Metadata = {
export default function SettlementLanding() {
return (
-
- Across Settlement
+
+
+
+
+
+
);
}
diff --git a/src/app/_assets/settlement-2.png b/src/app/_assets/settlement-2.png
new file mode 100644
index 0000000..996175b
Binary files /dev/null and b/src/app/_assets/settlement-2.png differ
diff --git a/src/app/_assets/settlement-hero.png b/src/app/_assets/settlement-hero.png
new file mode 100644
index 0000000..75b2e93
Binary files /dev/null and b/src/app/_assets/settlement-hero.png differ
diff --git a/src/app/_assets/settlement-layer.png b/src/app/_assets/settlement-layer.png
new file mode 100644
index 0000000..24aad3f
Binary files /dev/null and b/src/app/_assets/settlement-layer.png differ
diff --git a/src/app/_components/get-started-section.tsx b/src/app/_components/get-started-section.tsx
new file mode 100644
index 0000000..e55fca6
--- /dev/null
+++ b/src/app/_components/get-started-section.tsx
@@ -0,0 +1,70 @@
+import { ArrowRightIcon } from "@/app/_components/icons";
+import { Text } from "@/app/_components/text";
+import { INFORMATION_LINKS } from "@/app/_constants";
+import { ReactNode } from "react";
+import { twJoin } from "tailwind-merge";
+
+const variants = {
+ teal: {
+ textClassName: "text-teal-100",
+ bgClassName: "bg-teal-100",
+ opacityBgClassName: "bg-teal-100/[.05]",
+ },
+ purple: {
+ textClassName: "text-purple-100",
+ bgClassName: "bg-purple-100",
+ opacityBgClassName: "bg-purple-100/[.05]",
+ },
+};
+
+export function GetStartedSection(props: {
+ Image: ReactNode;
+ variant: "teal" | "purple";
+}) {
+ return (
+
+ {props.Image}
+
+ Ready to get started?
+
+
+
+ );
+}
diff --git a/src/app/_components/icons/gradient/checkmark.tsx b/src/app/_components/icons/gradient/checkmark.tsx
index 3aa7239..6317280 100644
--- a/src/app/_components/icons/gradient/checkmark.tsx
+++ b/src/app/_components/icons/gradient/checkmark.tsx
@@ -8,6 +8,7 @@ export function CheckmarkIcon(props: SVGProps) {
viewBox="0 0 96 96"
fill="none"
xmlns="http://www.w3.org/2000/svg"
+ {...props}
>
) {
viewBox="0 0 96 96"
fill="none"
xmlns="http://www.w3.org/2000/svg"
+ {...props}
>
& {
+export type Props = ComponentProps<"div"> & {
title: string;
titleClassName: string;
value: string;
diff --git a/src/app/_components/stats-row.tsx b/src/app/_components/stats-row.tsx
new file mode 100644
index 0000000..82ca49b
--- /dev/null
+++ b/src/app/_components/stats-row.tsx
@@ -0,0 +1,70 @@
+import { StatBox, Props as StatBoxProps } from "./stat-box";
+
+import { getProtocolStats } from "../_lib/scraper";
+import { humanReadableNumber } from "../_lib/format";
+
+async function getFormattedStatsData() {
+ const protocolStats = await getProtocolStats({
+ revalidate: 24 * 60 * 60, // Update once a day
+ });
+
+ return {
+ totalVolumeUsd: `$${humanReadableNumber(protocolStats.totalVolumeUsd)}`,
+ totalDeposits: `${humanReadableNumber(protocolStats.totalDeposits)}`,
+ avgFillTimeInMinutes: `${protocolStats.avgFillTimeInMinutes < 1 ? "<" : ""} ${Math.max(
+ protocolStats.avgFillTimeInMinutes,
+ 1,
+ )}m`,
+ bridgeFee: "<$1",
+ };
+}
+
+type OverrideStatBoxProps = Pick<
+ StatBoxProps,
+ "titleClassName" | "className" | "dividerClassName"
+>;
+
+export async function StatsRow(props: {
+ volumeBoxProps?: OverrideStatBoxProps;
+ transactionBoxProps?: OverrideStatBoxProps;
+ avgFillTimeBoxProps?: OverrideStatBoxProps;
+ bridgeFeeBoxProps?: OverrideStatBoxProps;
+}) {
+ const formattedStatsData = await getFormattedStatsData();
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/_components/supported-chains-section.tsx b/src/app/_components/supported-chains-section.tsx
new file mode 100644
index 0000000..8f92b36
--- /dev/null
+++ b/src/app/_components/supported-chains-section.tsx
@@ -0,0 +1,87 @@
+import { twMerge } from "@/app/_lib/tw-merge";
+import {
+ EthereumIcon,
+ OptimismIcon,
+ PolygonIcon,
+ ArbitrumIcon,
+ BaseIcon,
+ ZkSyncIcon,
+} from "@/app/_components/icons";
+import { Text } from "@/app/_components/text";
+
+const chains = [
+ {
+ label: "Ethereum Mainnet",
+ Icon: EthereumIcon,
+ },
+ {
+ label: "Optimism",
+ Icon: OptimismIcon,
+ },
+ {
+ label: "Polygon Network",
+ Icon: PolygonIcon,
+ iconClassName: "h-8 w-9 md:h-10 md:w-10",
+ },
+ {
+ label: "Arbitrum One",
+ Icon: ArbitrumIcon,
+ },
+ {
+ label: "Base",
+ Icon: BaseIcon,
+ },
+ {
+ label: "zkSync Era",
+ Icon: ZkSyncIcon,
+ },
+];
+
+const variants = {
+ teal: {
+ textClassName: "text-teal-100",
+ bgClassName: "bg-teal-100/[.05]",
+ },
+ purple: {
+ textClassName: "text-purple-100",
+ bgClassName: "bg-purple-100/[.05]",
+ },
+};
+
+export function SupportedChainsSection(props: { variant: "teal" | "purple" }) {
+ return (
+
+
+
+ well connected
+
+
+ Supported Chains
+
+
+
+ {chains.map((chain, index) => (
+
+
+
+
+
+ {chain.label}
+
+
+ ))}
+
+
+ );
+}