| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- import ArrowForward from "@mui/icons-material/ArrowForward";
- import { Box, Button, Grid, Typography } from "@mui/material";
- import {
- Link as RouterLink,
- PageProps,
- graphql,
- useStaticQuery
- } from "gatsby";
- import React, { useEffect, useState } from "react";
- import GridWithCards from "../components/GridWithCards";
- import HeroText from "../components/HeroText";
- import Layout from "../components/Layout";
- import { SEO } from "../components/SEO";
- import { portal as portalUrl } from "../utils/urls";
- import { gsap } from "gsap";
- import { ScrollTrigger } from "gsap/ScrollTrigger";
- import apps from "../images/index/apps2.png";
- import blob from "../images/index/blob.svg";
- import cross from "../images/index/cross.svg";
- import cube from "../images/index/cube.svg";
- import portal from "../images/index/portal.png";
- import protocols from "../images/index/protocol_new.png";
- import shape1 from "../images/index/shape1.svg";
- import shape from "../images/shape.png";
- import shape2 from "../images/shape2.png";
- import { Totals, NotionalTvl } from "../components/ExplorerStats/ExplorerStats";
- import { amountFormatter } from "../utils/explorer";
- const featuredNumber = { fontSize: 42, fontFamily: "Suisse BP Intl", fontWeight: "bold" };
- const statsBaseUrl = "https://europe-west3-wormhole-315720.cloudfunctions.net/mainnet-"
- const IndexPage = ({ location }: PageProps) => {
- const { site } = useStaticQuery<IndexQueryType>(IndexStaticQuery)
- const [tvl, setTvl] = useState<number | undefined>(undefined)
- const [messageTotal, setMessageTotal] = useState<number | undefined>(undefined)
- let statsInterval: NodeJS.Timer | undefined = undefined
- const controller = new AbortController()
- const { signal } = controller
- const logo = {
- "@type": "ImageObject",
- "url": `${site.siteMetadata.siteUrl}/logo-and-name-stacked.png`,
- "height": "146",
- "width": "146"
- }
- const structuredData = {
- "@context": "https://schema.org",
- "@type": "Organization",
- "@id": "https://wormholenetwork.com#organization",
- mainEntityOfPage: "https://wormholenetwork.com#organization",
- url: "https://wormholenetwork.com",
- name: "Wormhole",
- sameAs: [
- "https://github.com/certusone/wormhole",
- "https://t.me/wormholecrypto",
- "https://twitter.com/wormholecrypto",
- "https://wormholebridge.com",
- "https://wormholecrypto.medium.com",
- "https://discord.gg/wormholecrypto",
- ],
- alternateName: [
- "wormhole network",
- "wormhole protocol",
- "wormhole bridge",
- "wormhole crypto",
- "certus one wormhole",
- "solana wormhole",
- "SOL wormhole",
- "terra wormhole",
- "LUNA wormhole",
- "ethereum wormhole",
- "ETH wormhole",
- "binance wormhole",
- "BSC wormhole",
- "oasis wormhole",
- "ROSE wormhole",
- "avalanche wormhole",
- "AVAX wormhole"
- ],
- description: "A cross-chain messaging protocol.",
- image: logo,
- logo: logo
- }
- const headerImage = React.useRef<HTMLCanvasElement>(null);
- const gradient1 = React.useRef<HTMLCanvasElement>(null);
- const gradient2 = React.useRef<HTMLCanvasElement>(null);
- function fetchStats() {
- const tvlUrl = `${statsBaseUrl}notionaltvl`
- const messagesUrl = `${statsBaseUrl}totals`
- fetch(tvlUrl, { signal }).then((res) => {
- if (res.ok) return res.json();
- }).then((result: NotionalTvl) => {
- setTvl(result.AllTime["*"]["*"].Notional);
- }, (error) => {
- if (error.name !== "AbortError") console.error("failed fetching notional TVL. error: ", error);
- });
- fetch(messagesUrl, { signal }).then((res) => {
- if (res.ok) return res.json();
- }).then((result: Totals) => {
- setMessageTotal(result.TotalCount["*"]);
- }, (error) => {
- if (error.name !== "AbortError") console.error("failed fetching totals. error: ", error);
- });
- }
- useEffect(() => {
- statsInterval = setInterval(fetchStats, 30000)
- gsap.registerPlugin(ScrollTrigger);
- gsap.from(headerImage.current, {
- scale: 1.1,
- duration: 10,
- delay: 1,
- rotation: 3,
- ease: "Power3.easeOut",
- })
- gsap.to(gradient1.current, {
- scale: 1.2,
- ease: "Power3.easeOut",
- x: 300,
- scrollTrigger: {
- trigger: gradient1.current,
- start: "-0% 0%",
- end: "+=500",
- scrub: 1,
- },
- })
- gsap.from(gradient2.current, {
- scale: 0.5,
- ease: "Power3.easeOut",
- scrollTrigger: {
- trigger: gradient2.current,
- start: "-50% 50%",
- end: "+=1000",
- scrub: 1,
- },
- })
- return function cleanup() {
- // clear any ongoing intervals
- if (statsInterval) {
- clearInterval(statsInterval);
- }
- // abort any in-flight requests
- controller.abort();
- }
- }, [])
- return (
- <Layout>
- <SEO
- // use default title for index
- description="The best of blockchains. Move information and value anywhere."
- pathname={location.pathname}
- >
- <script type="application/ld+json">
- {JSON.stringify(structuredData, undefined, 4)}
- </script>
- </SEO>
- <Box sx={{ position: "relative", marginTop: 21 }}>
- <Box
- ref={headerImage}
- sx={{
- position: "absolute",
- zIndex: -1,
- transform: "translate(0px, -25%)",
- background: `url(${shape1})`,
- backgroundRepeat: "no-repeat",
- backgroundPosition: "top -240px center",
- backgroundSize: "2070px 1155px",
- width: "100%",
- height: 1155,
- }}
- />
- <HeroText
- maxWidth={600}
- heroSpans={["The best of", "blockchains"]}
- subtitleText="Move information and value anywhere."
- />
- <Box
- sx={{
- m: "auto",
- maxWidth: { xs: 240, sm: 600 },
- textAlign: "center",
- }}
- >
- <Box
- sx={{
- width: "calc( 100% - 16px )",
- mx: "auto",
- mt: 15.5,
- display: "flex",
- flexWrap: "wrap",
- justifyContent: "center",
- }}
- >
- {tvl && <Box
- sx={{
- mt: 2,
- mx: 1,
- pt: { xs: 1, sm: 0 },
- display: "flex",
- alignItems: "center",
- justifyContent: "space-evenly",
- flexBasis: { xs: "100%", sm: "calc(33.33333% - 16px)" },
- borderTop: "1px solid white",
- }}
- >
- <Typography sx={featuredNumber}>${amountFormatter(tvl)}</Typography>
- <Typography variant="body2">in TVL</Typography>
- </Box>}
- <Box
- sx={{
- mt: 2,
- mx: 1,
- pt: { xs: 1, sm: 0 },
- display: "flex",
- alignItems: "center",
- justifyContent: "space-evenly",
- flexBasis: { xs: "100%", sm: "calc(33.33333% - 16px)" },
- borderTop: "1px solid white",
- }}
- >
- <Typography sx={featuredNumber}>7</Typography>
- <Typography variant="body2">chain integrations</Typography>
- </Box>
- {messageTotal && <Box
- sx={{
- mt: 2,
- mx: 1,
- pt: { xs: 1, sm: 0 },
- display: "flex",
- alignItems: "center",
- justifyContent: "space-evenly",
- flexBasis: { xs: "100%", sm: "calc(33.33333% - 16px)" },
- borderTop: "1px solid white",
- }}
- >
- <Typography sx={featuredNumber}>
- {amountFormatter(messageTotal, 0)}
- </Typography>
- <Typography variant="body2">txs</Typography>
- </Box>}
- </Box>
- </Box>
- </Box>
- <Box sx={{ position: 'relative' }}>
- <Box
- ref={gradient1}
- sx={{
- position: "absolute",
- zIndex: -1,
- top: '50%',
- background: 'radial-gradient(closest-side at 50% 50%, #E72850 0%, #E7285000 100%)',
- transform: 'matrix(0.96, 0.29, -0.29, 0.96, 0, 0)',
- left: '60%',
- width: 1645,
- height: 903,
- pointerEvents: 'none',
- opacity: 0.7,
- }}
- />
- <Box
- ref={gradient2}
- sx={{
- position: "absolute",
- zIndex: -1,
- top: '65%',
- background: 'radial-gradient(closest-side at 50% 50%, #5189C8 0%, #5189C800 100%) ',
- transform: 'matrix(0.67, 0.74, -0.74, 0.67, 0, 0)',
- left: '5%',
- width: 1136,
- height: 1489,
- pointerEvents: 'none',
- opacity: 0.64,
- }}
- />
- <Box
- sx={{
- position: "absolute",
- zIndex: -1,
- background: `url(${shape})`,
- backgroundSize: 'contain',
- top: -100,
- right: '70vw',
- width: 1363,
- height: 1130,
- pointerEvents: 'none',
- display: { xs: 'none', md: 'block' },
- }}
- />
- <Box
- sx={{
- display: "flex",
- flexWrap: "wrap",
- maxWidth: 1220,
- px: 3.75,
- mt: 35,
- mx: "auto",
- alignItems: "center",
- justifyContent: "center",
- }}
- >
- <Box
- sx={{
- flexBasis: { xs: "100%", md: "40%" },
- flexGrow: 1,
- }}
- >
- <Box sx={{ px: { xs: 0, md: 4 } }}>
- <Box sx={{ maxWidth: 348, mx: "auto" }}>
- <Typography variant="h3">
- <Box component="span" sx={{ color: "#FFCE00" }}>
- Protocol:{" "}
- </Box>
- <Box component="span" sx={{ display: "inline-block" }}>
- the core layer
- </Box>
- </Typography>
- <Typography sx={{ mt: 2 }}>
- The foundation that an ecosystem of apps is built on top of.
- </Typography>
- <Button
- component={RouterLink}
- to="/buidl/"
- sx={{ mt: 3 }}
- variant="outlined"
- color="inherit"
- endIcon={<ArrowForward />}
- >
- Learn More
- </Button>
- </Box>
- </Box>
- </Box>
- <Box
- sx={{
- mt: { xs: 8, md: null },
- flexBasis: { xs: "100%", md: "60%" },
- textAlign: "center",
- flexGrow: 1,
- }}
- >
- <Box
- component="img"
- src={protocols}
- alt=""
- sx={{ maxWidth: "100%" }}
- />
- </Box>
- </Box>
- </Box>
- <Box
- sx={{
- display: "flex",
- flexWrap: "wrap-reverse",
- maxWidth: 1220,
- px: 3.75,
- mt: 15.5,
- mx: "auto",
- alignItems: "center",
- justifyContent: "center",
- }}
- >
- <Box
- sx={{
- mt: { xs: 8, md: null },
- flexBasis: { xs: "100%", md: "60%" },
- textAlign: "center",
- flexGrow: 1,
- }}
- >
- <Box component="img" src={apps} alt="" sx={{ maxWidth: "100%" }} />
- </Box>
- <Box sx={{ flexBasis: { xs: "100%", md: "40%" }, flexGrow: 1 }}>
- <Box sx={{ px: { xs: 0, md: 4 } }}>
- <Box sx={{ maxWidth: 348, mx: "auto" }}>
- <Typography variant="h3">
- <Box component="span" sx={{ color: "#FFCE00" }}>
- Apps:{" "}
- </Box>
- <Box component="span">endless possibilities</Box>
- </Typography>
- <Typography sx={{ mt: 2 }}>
- Apps can now live across chains at once and integrate the best
- of each.
- </Typography>
- <Button
- component={RouterLink}
- to="/apps/"
- sx={{ mt: 3 }}
- variant="outlined"
- color="inherit"
- endIcon={<ArrowForward />}
- >
- Learn More
- </Button>
- </Box>
- </Box>
- </Box>
- </Box>
- <Box sx={{ position: 'relative' }}>
- <Box
- sx={{
- position: "absolute",
- zIndex: -1,
- background: `url(${shape2})`,
- backgroundSize: 'contain',
- top: '50%',
- transform: 'translateY(-50%)',
- left: '75vw',
- width: 1612,
- height: 1316,
- pointerEvents: 'none',
- display: { xs: 'none', md: 'block' },
- }}
- />
- <Box
- sx={{
- display: "flex",
- flexWrap: "wrap",
- maxWidth: 1220,
- px: 3.75,
- mt: 15.5,
- mx: "auto",
- alignItems: "center",
- justifyContent: "center",
- }}
- >
- <Box
- sx={{
- flexBasis: { xs: "100%", md: "40%" },
- flexGrow: 1,
- }}
- >
- <Box sx={{ px: { xs: 0, md: 4 } }}>
- <Box sx={{ maxWidth: 340, mx: "auto" }}>
- <Typography variant="h3">
- <Box component="span" sx={{ color: "#FFCE00" }}>
- Portal:{" "}
- </Box>
- <Box component="span" sx={{ display: "inline-block" }}>
- a token bridge
- </Box>
- </Typography>
- <Typography sx={{ mt: 2 }}>
- Never have to retrace your steps, with unlimited transfers
- across chains for tokens and NFTs wrapped by Wormhole.
- </Typography>
- <Button
- href={portalUrl}
- sx={{ mt: 3 }}
- variant="outlined"
- color="inherit"
- endIcon={<ArrowForward />}
- >
- Learn More
- </Button>
- </Box>
- </Box>
- </Box>
- <Box
- sx={{
- mt: { xs: 8, md: null },
- flexBasis: { xs: "100%", md: "60%" },
- textAlign: "center",
- flexGrow: 1,
- }}
- >
- <Button variant="text" href={portalUrl} sx={{
- '&:hover': {
- background: 'transparent'
- },
- 'span': {
- display: 'none'
- }
- }}>
- <Box component="img" src={portal} alt="" sx={{ maxWidth: "100%" }} />
- </Button>
- </Box>
- </Box>
- </Box>
- <Box sx={{ textAlign: "center", mt: 12.5, px: 2 }}>
- <Typography variant="h3">
- <Box component="span" sx={{ color: "#FFCE00" }}>
- Cross-chain
- </Box>
- <Box component="span"> everything</Box>
- </Typography>
- <Typography sx={{ mt: 2, maxWidth: 480, mx: "auto", fontWeight: 300 }}>
- Each blockchain has a distinct strength. Wormhole lets you get the
- best out of every blockchain without compromise.
- </Typography>
- </Box>
- <Box sx={{ maxWidth: 1220, mx: "auto", mt: 12, px: 3.75 }}>
- <GridWithCards
- data={[
- {
- src: cross,
- size: 220,
- header: "Never stop expanding",
- description:
- "Chains, information, and users are growing everyday. Build on a protocol that is set up to scale, with no limits, right from the start.",
- },
- {
- src: blob,
- size: 220,
- header: "Explore and experiment",
- description:
- "Now is the time to explore and experiment. The only limit to what you're able to build is your imagination.",
- },
- {
- src: cube,
- size: 220,
- header: "Power your project",
- description:
- "Join the growing list of projects that are composing, raising, and succeeding with Wormhole core layer.",
- },
- ]}
- />
- </Box>
- </Layout>
- );
- };
- type IndexQueryType = {
- site: {
- siteMetadata: {
- siteUrl: string
- }
- }
- }
- const IndexStaticQuery = graphql`
- query Index {
- site {
- siteMetadata {
- siteUrl
- }
- }
- }
- `
- export default IndexPage;
|