├── pages
├── .DS_Store
├── api
│ ├── .DS_Store
│ ├── contract
│ │ └── dmt-erc1155.js
│ └── nft
│ │ └── [id].js
├── _app.js
├── index.js
├── intro.js
├── farms
│ ├── index.js
│ └── [farmId].js
└── gallery.js
├── public
├── .DS_Store
├── logo.png
├── favicon.ico
├── favicon-16x16.png
├── favicon-32x32.png
├── images
│ ├── bg-plain.png
│ ├── dm-logo.png
│ ├── farm-dmt.png
│ ├── nft-dmt.png
│ ├── preview.png
│ ├── bg-nebula.png
│ ├── bg-stars-1.png
│ ├── bg-stars-2.png
│ ├── dm-logo-ring.png
│ ├── home-farm-dmt.png
│ ├── home-nft-dmt.png
│ ├── splash-logo-bot.png
│ ├── splash-logo-top.png
│ └── dmt-video-placeholder.png
├── mstile-150x150.png
├── apple-touch-icon.png
├── android-chrome-192x192.png
├── android-chrome-256x256.png
├── browserconfig.xml
├── site.webmanifest
└── safari-pinned-tab.svg
├── components
├── .DS_Store
├── layout
│ ├── Main.js
│ ├── Container.js
│ ├── index.js
│ ├── Header.js
│ ├── Drawer.js
│ └── Footer.js
├── story
│ ├── index.js
│ ├── NFT2.js
│ ├── NFT4.js
│ ├── NFT3.js
│ ├── NFT5.js
│ ├── NFT6.js
│ ├── NFT1.js
│ └── NFT7.js
├── splash
│ ├── splash.css
│ └── Splash.js
├── utils
│ └── InternalLink.js
├── icons
│ ├── Etherscan.js
│ ├── YtslaLogoText.js
│ ├── LogoLight.js
│ ├── YtslaLogoIcon.js
│ ├── WalletConnectLogoIcon.js
│ ├── OpenseaLogoIcon.js
│ ├── YtslaLogoFull.js
│ ├── UniswapLogoIcon.js
│ └── MetaMaskLogoIcon.js
├── background
│ ├── Background.js
│ └── background.css
├── forms
│ └── FormErrors.js
├── farms
│ ├── DepositOptions.js
│ ├── config.js
│ ├── EarnCard.js
│ ├── LandingCard.js
│ ├── DepositCard.js
│ ├── DepositModal.js
│ └── WithdrawModal.js
├── DocHead.js
├── spinners
│ └── Inline.js
├── gallery
│ ├── InputPassword.js
│ └── GalleryCard.js
├── wallet
│ ├── WalletModal.js
│ └── ConnectButton.js
└── countdown
│ └── CountdownModal.js
├── __MACOSX
├── pages
│ ├── ._.DS_Store
│ └── api
│ │ └── ._.DS_Store
├── public
│ └── ._.DS_Store
└── components
│ └── ._.DS_Store
├── README.md
├── theme
├── styles.js
├── index.js
├── component-link.js
└── component-button.js
├── hooks
├── usePrevious.js
├── useDidMount.js
├── usePageTitle.js
├── useEthPrice.js
├── useInterval.js
└── useContracts.js
├── lib
├── scroll.js
├── uniswapPair.js
├── numeric.js
├── wallet.js
├── stakingERC20.js
├── stakingERC1155.js
└── erc20.js
└── package.json
/pages/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/pages/.DS_Store
--------------------------------------------------------------------------------
/public/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/.DS_Store
--------------------------------------------------------------------------------
/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/logo.png
--------------------------------------------------------------------------------
/pages/api/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/pages/api/.DS_Store
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/components/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/components/.DS_Store
--------------------------------------------------------------------------------
/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/favicon-32x32.png
--------------------------------------------------------------------------------
/public/images/bg-plain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/bg-plain.png
--------------------------------------------------------------------------------
/public/images/dm-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/dm-logo.png
--------------------------------------------------------------------------------
/public/images/farm-dmt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/farm-dmt.png
--------------------------------------------------------------------------------
/public/images/nft-dmt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/nft-dmt.png
--------------------------------------------------------------------------------
/public/images/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/preview.png
--------------------------------------------------------------------------------
/public/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/mstile-150x150.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/images/bg-nebula.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/bg-nebula.png
--------------------------------------------------------------------------------
/public/images/bg-stars-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/bg-stars-1.png
--------------------------------------------------------------------------------
/public/images/bg-stars-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/bg-stars-2.png
--------------------------------------------------------------------------------
/public/images/dm-logo-ring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/dm-logo-ring.png
--------------------------------------------------------------------------------
/public/images/home-farm-dmt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/home-farm-dmt.png
--------------------------------------------------------------------------------
/public/images/home-nft-dmt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/home-nft-dmt.png
--------------------------------------------------------------------------------
/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/android-chrome-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/android-chrome-256x256.png
--------------------------------------------------------------------------------
/public/images/splash-logo-bot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/splash-logo-bot.png
--------------------------------------------------------------------------------
/public/images/splash-logo-top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/splash-logo-top.png
--------------------------------------------------------------------------------
/public/images/dmt-video-placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/DarkMatter/HEAD/public/images/dmt-video-placeholder.png
--------------------------------------------------------------------------------
/__MACOSX/pages/._.DS_Store:
--------------------------------------------------------------------------------
1 | Mac OS X 2 F x @ ATTR x x
--------------------------------------------------------------------------------
/__MACOSX/public/._.DS_Store:
--------------------------------------------------------------------------------
1 | Mac OS X 2 F x @ ATTR x x
--------------------------------------------------------------------------------
/__MACOSX/components/._.DS_Store:
--------------------------------------------------------------------------------
1 | Mac OS X 2 F x @ ATTR x x
--------------------------------------------------------------------------------
/__MACOSX/pages/api/._.DS_Store:
--------------------------------------------------------------------------------
1 | Mac OS X 2 F x @ ATTR x x
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dark Matter Token Website
2 | Uses [Next.js](https://nextjs.org/) and [Chakra UI](https://chakra-ui.com/).
3 |
4 | ## Development
5 |
6 | `npm run dev`
--------------------------------------------------------------------------------
/components/layout/Main.js:
--------------------------------------------------------------------------------
1 | import { Box } from "@chakra-ui/core";
2 |
3 | const Main = ({ children }) => (
4 |
5 | {children}
6 |
7 | );
8 |
9 | export default Main;
--------------------------------------------------------------------------------
/theme/styles.js:
--------------------------------------------------------------------------------
1 | const styles = {
2 | global: {
3 | "html, body": {
4 | height: "100%",
5 | minHeight: "100%",
6 | },
7 | "body": {
8 | background: "gray.50",
9 | },
10 | },
11 | };
12 |
13 | export default styles;
14 |
--------------------------------------------------------------------------------
/hooks/usePrevious.js:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from "react";
2 |
3 | const usePrevious = (value) => {
4 | const ref = useRef();
5 |
6 | useEffect(() => {
7 | ref.current = value;
8 | });
9 |
10 | return ref.current;
11 | };
12 |
13 | export default usePrevious;
14 |
--------------------------------------------------------------------------------
/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #ffc40d
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/hooks/useDidMount.js:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from "react";
2 |
3 | const useDidMount = () => {
4 | const didMountRef = useRef(false);
5 |
6 | useEffect(() => {
7 | didMountRef.current = true;
8 | }, []);
9 |
10 | return didMountRef.current;
11 | };
12 |
13 | export default useDidMount;
14 |
--------------------------------------------------------------------------------
/components/story/index.js:
--------------------------------------------------------------------------------
1 | import Level1 from "./NFT1";
2 | import Level2 from "./NFT2";
3 | import Level3 from "./NFT3";
4 | import Level4 from "./NFT4";
5 | import Level5 from "./NFT5";
6 | import Level6 from "./NFT6";
7 | import Level7 from "./NFT7";
8 |
9 | export { Level1, Level2, Level3, Level4, Level5, Level6, Level7 };
10 |
--------------------------------------------------------------------------------
/hooks/usePageTitle.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 |
3 | const usePageTitle = title => {
4 | const [pageTitle, setPageTitle] = useState(`${title} | Dark Matter`);
5 |
6 | useEffect(() => {
7 | document.title = pageTitle;
8 | }, [pageTitle]);
9 |
10 | return [setPageTitle];
11 | };
12 |
13 | export default usePageTitle;
14 |
--------------------------------------------------------------------------------
/theme/index.js:
--------------------------------------------------------------------------------
1 | import { extendTheme } from "@chakra-ui/core";
2 |
3 | import Button from "./component-button.js";
4 | import Link from "./component-link.js";
5 | import styles from "./styles.js";
6 |
7 | const overrides = {
8 | components: {
9 | Button,
10 | Link,
11 | },
12 | styles,
13 | }
14 |
15 | export default extendTheme(overrides);
16 |
--------------------------------------------------------------------------------
/lib/scroll.js:
--------------------------------------------------------------------------------
1 | const scrollToPosition = (top = 0) => {
2 | try {
3 | /**
4 | * Latest API
5 | */
6 | window.scroll({
7 | top: top,
8 | left: 0,
9 | behavior: "smooth",
10 | });
11 | } catch (_) {
12 | /**
13 | * Fallback
14 | */
15 | window.scrollTo(0, top);
16 | }
17 | };
18 |
19 | export {
20 | scrollToPosition,
21 | };
22 |
--------------------------------------------------------------------------------
/components/layout/Container.js:
--------------------------------------------------------------------------------
1 | import { Flex } from "@chakra-ui/core";
2 |
3 | import Splash from "../splash/Splash";
4 | import Background from "../background/Background";
5 |
6 | const Container = ({ children }) => (
7 |
8 |
9 |
10 | {children}
11 |
12 | );
13 |
14 | export default Container;
15 |
--------------------------------------------------------------------------------
/components/splash/splash.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Splash animations.
3 | */
4 | .splashLogoIn {
5 | opacity: 1!important;
6 | }
7 |
8 | .splashLogoOut {
9 | transition: all 1.5s ease-in!important;
10 | opacity: 0!important;
11 | }
12 |
13 | .splashTopShutter {
14 | opacity: 0.9;
15 | transform: translateY(-100%);
16 | }
17 |
18 | .splashBotShutter {
19 | opacity: 0.9;
20 | transform: translateY(100%);
21 | }
--------------------------------------------------------------------------------
/hooks/useEthPrice.js:
--------------------------------------------------------------------------------
1 | import CoinGecko from "coingecko-api";
2 | import { useEffect, useState } from "react";
3 |
4 | export function useEthPrice() {
5 | const client = new CoinGecko();
6 | const [ethUSD, setEthUsd] = useState(0);
7 |
8 | useEffect(() => {
9 | client.simple.price({ ids: ['ethereum'], vs_currencies: 'usd' }).then(({ data, success }) => {
10 | if (success) {
11 | setEthUsd(data.ethereum.usd);
12 | }
13 | });
14 | }, []);
15 |
16 | return { ethUSD };
17 | };
--------------------------------------------------------------------------------
/pages/api/contract/dmt-erc1155.js:
--------------------------------------------------------------------------------
1 | export default (req, res) => {
2 | res.statusCode = 200;
3 | res.json({
4 | name: "Dark Matter Ltd.",
5 | description: "Dark Matter presents: Mission to Marp. Users will navigate their way through a narrative-driven augmented reality game utilizing DeFi yield farming and collectible NFT's. Dark Matter is the next evolution in yield farming protocols.",
6 | image: "https://darkmatter.finance/logo.png",
7 | external_link: "https://darkmatter.finance",
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/public/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "short_name": "",
4 | "icons": [
5 | {
6 | "src": "/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/android-chrome-256x256.png",
12 | "sizes": "256x256",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/lib/uniswapPair.js:
--------------------------------------------------------------------------------
1 | import {
2 | ChainId,
3 | Token,
4 | WETH,
5 | Fetcher,
6 | Route,
7 | } from '@uniswap/sdk';
8 |
9 | export const create = (tokenAddress, provider) => {
10 | const token = new Token(ChainId.MAINNET, tokenAddress, 18); // ChainId.MAINNET
11 |
12 | const fetchPairData = () => Fetcher.fetchPairData(token, WETH[ChainId.MAINNET], provider);
13 |
14 | const getPrice = async () => {
15 | const pair = await fetchPairData();
16 | const route = new Route([pair], token);
17 |
18 | return route.midPrice.toSignificant(6);
19 | };
20 |
21 | return { getPrice };
22 | };
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start"
9 | },
10 | "dependencies": {
11 | "@chakra-ui/core": "^1.0.0-rc.5",
12 | "@chakra-ui/icons": "^1.0.0-rc.5",
13 | "@uniswap/sdk": "^3.0.3",
14 | "coingecko-api": "^1.0.10",
15 | "ethers": "^5.0.17",
16 | "lodash": "^4.17.20",
17 | "next": "9.5.4",
18 | "react": "16.13.1",
19 | "react-dom": "16.13.1",
20 | "react-icons": "^3.11.0",
21 | "use-wallet": "^0.8.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/hooks/useInterval.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from "react";
2 |
3 | const useInterval = (callback, delay) => {
4 | const savedCallback = useRef();
5 |
6 | /**
7 | * Remember the latest callback.
8 | */
9 | useEffect(() => {
10 | savedCallback.current = callback;
11 | }, [callback]);
12 |
13 | /**
14 | * Set up the interval.
15 | */
16 | useEffect(() => {
17 | function tick() {
18 | savedCallback.current();
19 | }
20 |
21 | if (delay !== null) {
22 | let id = setInterval(tick, delay);
23 |
24 | return () => clearInterval(id);
25 | }
26 | }, [delay]);
27 | };
28 |
29 | export default useInterval;
--------------------------------------------------------------------------------
/lib/numeric.js:
--------------------------------------------------------------------------------
1 | import _isNaN from "lodash/isNaN";
2 | import _isNull from "lodash/isNull";
3 |
4 | const formatNumber = (
5 | value,
6 | decimalPlaces = 2,
7 | defaultValue = "...",
8 | prefix = "",
9 | suffix = ""
10 | ) => {
11 | const parsedValue = parseFloat("" + value);
12 |
13 | if (!_isNaN(parsedValue))
14 | return `${prefix}${parsedValue.toFixed(decimalPlaces)}${suffix}`;
15 |
16 | return defaultValue;
17 | };
18 |
19 | const isValidNumber = (value, min = null, max = null) => {
20 | const parsedValue = parseFloat("" + value);
21 |
22 | if (
23 | _isNaN(parsedValue) ||
24 | (!_isNull(min) && parsedValue < min) ||
25 | (!_isNull(max) && parsedValue > max)
26 | ) {
27 | return false;
28 | }
29 |
30 | return true;
31 | };
32 |
33 | export { formatNumber, isValidNumber };
34 |
--------------------------------------------------------------------------------
/components/layout/index.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useRouter } from "next/router";
3 |
4 | import useDidMount from "../../hooks/useDidMount";
5 | import { scrollToPosition } from "../../lib/scroll";
6 |
7 | import Container from "./Container";
8 | import Header from "./Header";
9 | import Main from "./Main";
10 | import Footer from "./Footer";
11 |
12 | const Layout = ({ children }) => {
13 | const didMount = useDidMount();
14 | const router = useRouter();
15 | const { asPath } = router;
16 |
17 | /**
18 | * Scroll to top on each route change using `asPath` (resolved path),
19 | * not `pathname` (may be a dynamic route).
20 | */
21 | useEffect(() => {
22 | if (didMount) {
23 | scrollToPosition();
24 | }
25 | }, [asPath]);
26 |
27 | return (
28 |
29 |
30 | {children}
31 |
32 |
33 | );
34 | };
35 |
36 | export default Layout;
--------------------------------------------------------------------------------
/components/utils/InternalLink.js:
--------------------------------------------------------------------------------
1 | import { Link as ChakraLink } from "@chakra-ui/core";
2 | import NextLink from "next/link";
3 | import { useRouter } from "next/router";
4 |
5 | /**
6 | * Fixes NextJS's buggy implementation of react-router-dom.
7 | * Without this, Chakra's styleProps are ignored.
8 | */
9 | const InternalLink = ({
10 | href,
11 | shallow,
12 | children,
13 | prefetch,
14 | replace,
15 | scroll,
16 | linkAs,
17 | ...rest
18 | }) => {
19 | const linkProps = {
20 | as: linkAs,
21 | href,
22 | prefetch,
23 | replace,
24 | scroll,
25 | shallow,
26 | };
27 |
28 | const { pathname } = useRouter();
29 | const isActive = pathname === href;
30 |
31 | return (
32 |
33 |
34 | {children}
35 |
36 |
37 | );
38 | };
39 |
40 | export default InternalLink;
41 |
--------------------------------------------------------------------------------
/lib/wallet.js:
--------------------------------------------------------------------------------
1 | import _get from "lodash/get";
2 | import _includes from "lodash/includes";
3 |
4 | const connectWallet = (wallet, connector) => wallet.connect(connector);
5 |
6 | const getWalletConnectionStatus = wallet => wallet.status;
7 |
8 | const isWalletDisconnected = wallet => !!_includes(["disconnected", "error"], getWalletConnectionStatus(wallet));
9 |
10 | const isWalletConnecting = wallet => getWalletConnectionStatus(wallet) === "connecting";
11 |
12 | const isWalletConnected = wallet => getWalletConnectionStatus(wallet) === "connected";
13 |
14 | const getWalletAddress = wallet => {
15 | return wallet.account || _get(window, "ethereum.selectedAddress");
16 | }
17 |
18 | const shortenWalletAddress = address => `${address.substring(0, 6)}...${address.substring(address.length - 4, address.length)}`;
19 |
20 | export {
21 | connectWallet,
22 | getWalletConnectionStatus,
23 | isWalletDisconnected,
24 | isWalletConnecting,
25 | isWalletConnected,
26 | getWalletAddress,
27 | shortenWalletAddress,
28 | };
--------------------------------------------------------------------------------
/components/icons/Etherscan.js:
--------------------------------------------------------------------------------
1 | import { Icon } from "@chakra-ui/core";
2 |
3 | const EtherscanIcon = (props) => (
4 |
5 |
6 |
7 |
8 |
9 |
10 | );
11 |
12 | export default EtherscanIcon;
13 |
--------------------------------------------------------------------------------
/components/icons/YtslaLogoText.js:
--------------------------------------------------------------------------------
1 | import { Icon } from "@chakra-ui/core";
2 |
3 | const YtslaLogoText = (props) => (
4 |
5 |
6 |
7 |
8 |
9 | );
10 |
11 | export default YtslaLogoText;
12 |
--------------------------------------------------------------------------------
/components/background/Background.js:
--------------------------------------------------------------------------------
1 | import { useBreakpointValue } from "@chakra-ui/core";
2 |
3 | /**
4 | * Background: plain for smaller devices; animated for larger devices.
5 | */
6 | const styles = {
7 | bgPlain: {
8 | background: "url('/images/bg-plain.png') repeat-y center top",
9 | },
10 | bgLayer1: {
11 | backgroundImage: "url('/images/bg-stars-1.png')",
12 | },
13 | bgLayer2: {
14 | backgroundImage: "url('/images/bg-stars-2.png')",
15 | },
16 | bgLayer3: {
17 | backgroundImage: "url('/images/bg-nebula.png')",
18 | },
19 | };
20 |
21 | const Background = () => {
22 | const showPlain = useBreakpointValue({ base: false, lg: true });
23 |
24 | if (!showPlain) {
25 | return (
26 |
29 | );
30 | };
31 |
32 | return (
33 |
38 | );
39 | };
40 |
41 | export default Background;
42 |
--------------------------------------------------------------------------------
/components/forms/FormErrors.js:
--------------------------------------------------------------------------------
1 | import _map from "lodash/map";
2 | import _size from "lodash/size";
3 | import _isArray from "lodash/isArray";
4 |
5 | import {
6 | List,
7 | ListItem,
8 | ListIcon,
9 | } from "@chakra-ui/core";
10 |
11 | import { WarningIcon } from "@chakra-ui/icons";
12 |
13 | const FormErrors = ({ errors = null }) => {
14 | if (!_isArray(errors) || !_size(errors)) return null;
15 |
16 | return (
17 |
18 | {_map(
19 | errors,
20 | (errorCopy, index) => (
21 |
36 | {errorCopy}
37 |
38 | )
39 | )}
40 |
41 | );
42 | };
43 |
44 | export default FormErrors;
45 |
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import { ChakraProvider } from "@chakra-ui/core";
2 | import { UseWalletProvider } from "use-wallet";
3 |
4 | import DocHead from "../components/DocHead";
5 | import Layout from "../components/layout";
6 |
7 | import theme from "../theme";
8 |
9 | /**
10 | * CSS
11 | */
12 | import "../components/splash/splash.css";
13 | import "../components/background/background.css";
14 |
15 | /**
16 | * Required to set the default theme to `dark` due to a bug in Chakra V.1.0.0.
17 | * Once the patch is deployed, this can be removed and replaced with
18 | * setting the initialColorMode in the config object.
19 | */
20 | const fakeStorageManager = {
21 | get: () => "dark",
22 | set: (value) => {},
23 | type: "cookie",
24 | };
25 |
26 | /**
27 | * Uncomment to view the current theme object values.
28 | */
29 | // console.log(theme);
30 |
31 | const App = ({ Component, pageProps }) => (
32 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | );
46 |
47 | export default App;
48 |
--------------------------------------------------------------------------------
/components/icons/LogoLight.js:
--------------------------------------------------------------------------------
1 | import { Icon } from "@chakra-ui/core";
2 |
3 | const LogoLight = (props) => (
4 |
5 |
6 |
7 | );
8 |
9 | export default LogoLight;
10 |
--------------------------------------------------------------------------------
/components/icons/YtslaLogoIcon.js:
--------------------------------------------------------------------------------
1 | import { Icon } from "@chakra-ui/core";
2 |
3 | const YtslaLogoIcon = (props) => (
4 |
5 |
6 |
7 |
8 |
9 |
10 | );
11 |
12 | export default YtslaLogoIcon;
13 |
--------------------------------------------------------------------------------
/theme/component-link.js:
--------------------------------------------------------------------------------
1 | const Link = {
2 | variants: {
3 | transparent: {
4 | borderRadius: "lg",
5 | background: "none",
6 | boxShadow: "none",
7 | _hover: {
8 | background: "none",
9 | boxShadow: "none",
10 | },
11 | _focus: {
12 | background: "none",
13 | boxShadow: "none",
14 | },
15 | _active: {
16 | background: "none",
17 | boxShadow: "none",
18 | },
19 | },
20 | nav: {
21 | fontWeight: "bold",
22 | textTransform: "uppercase",
23 | display: "block",
24 | padding: "0.625rem 1rem",
25 | borderRadius: "lg",
26 | _hover: {
27 | textDecoration: "none",
28 | background: "purple.800",
29 | },
30 | },
31 | "drawer-nav": {
32 | fontWeight: "bold",
33 | textTransform: "uppercase",
34 | display: "block",
35 | padding: "0.625rem 2.5rem",
36 | _hover: {
37 | textDecoration: "none",
38 | background: "purple.800",
39 | },
40 | },
41 | primary: {
42 | textAlign: "center",
43 | fontWeight: "bold",
44 | textTransform: "uppercase",
45 | display: "block",
46 | padding: "0.625rem 1rem",
47 | borderRadius: "lg",
48 | background: "purple.900",
49 | _hover: {
50 | textDecoration: "none",
51 | background: "purple.800",
52 | },
53 | },
54 | "icon-only": {
55 | color: "whiteAlpha.500",
56 | _hover: {
57 | color: "purple.800",
58 | },
59 | transition: "all 0.15s ease-out",
60 | },
61 | },
62 | };
63 |
64 | export default Link;
65 |
--------------------------------------------------------------------------------
/components/farms/DepositOptions.js:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types";
2 | import { Flex } from "@chakra-ui/core";
3 |
4 | import DepositModal from "./DepositModal";
5 | import WithdrawModal from "./WithdrawModal";
6 |
7 | const DepositOptions = ({
8 | farmId,
9 | userTokenBalance,
10 | depositAmount,
11 | isDepositing,
12 | setIsDepositing,
13 | isWithdrawing,
14 | setIsWithdrawing,
15 | totalTokenRewards,
16 | usersTotalDepositied,
17 | }) => (
18 |
24 |
32 |
40 |
41 | );
42 |
43 | DepositOptions.propTypes = {
44 | farmId: PropTypes.string.isRequired,
45 | userTokenBalance: PropTypes.number,
46 | depositAmount: PropTypes.number,
47 | isDepositing: PropTypes.bool.isRequired,
48 | setIsDepositing: PropTypes.func.isRequired,
49 | isWithdrawing: PropTypes.bool.isRequired,
50 | setIsWithdrawing: PropTypes.func.isRequired,
51 | totalTokenRewards: PropTypes.number,
52 | usersTotalDepositied: PropTypes.number,
53 | };
54 |
55 | export default DepositOptions;
56 |
--------------------------------------------------------------------------------
/public/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
31 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | Flex,
3 | Box,
4 | Image,
5 | } from "@chakra-ui/core";
6 |
7 | import usePageTitle from "../hooks/usePageTitle";
8 | import InternalLink from "../components/utils/InternalLink";
9 |
10 | const Home = () => {
11 | usePageTitle("Home");
12 |
13 | const SectionCard = ({
14 | path,
15 | title,
16 | imageSrc,
17 | imageAlt,
18 | }) => (
19 |
20 |
39 |
44 |
45 |
46 | );
47 |
48 | return (
49 |
59 |
65 |
66 |
67 |
68 |
69 | );
70 | };
71 |
72 | export default Home;
73 |
--------------------------------------------------------------------------------
/components/background/background.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Background animation.
3 | */
4 | .bgContainer {
5 | position: absolute;
6 | z-index: -1;
7 | top: 0;
8 | left: 0;
9 | width: 100%;
10 | height: 100%;
11 | }
12 |
13 | .bgLayer {
14 | position: fixed;
15 | top: 0;
16 | left: 0;
17 | width: 100%;
18 | height: 100%;
19 | }
20 |
21 | .bgTiled {
22 | background-position: 0px 0px;
23 | background-repeat: repeat;
24 | }
25 |
26 | .bgLayer1 {
27 | z-index: 1;
28 | animation: 100s bgScroll1 infinite linear;
29 | }
30 |
31 | .bgLayer2 {
32 | z-index: 2;
33 | animation: 50s bgScroll2 infinite linear;
34 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
35 | filter: alpha(opacity=50);
36 | -moz-opacity: 0.5;
37 | -khtml-opacity: 0.5;
38 | opacity: 0.5;
39 | }
40 |
41 | .bgLayer3 {
42 | z-index: 3;
43 | }
44 |
45 | @-webkit-keyframes bgScroll1 {
46 | 100% {
47 | background-position: -500px 0px;
48 | }
49 | }
50 |
51 | @-moz-keyframes bgScroll1 {
52 | 100% {
53 | background-position: -500px 0px;
54 | }
55 | }
56 |
57 | @-o-keyframes bgScroll1 {
58 | 100% {
59 | background-position: -500px 0px;
60 | }
61 | }
62 |
63 | @-ms-keyframes bgScroll1 {
64 | 100% {
65 | background-position: -500px 0px;
66 | }
67 | }
68 |
69 | @keyframes bgScroll1 {
70 | 100% {
71 | background-position: -500px 0px;
72 | }
73 | }
74 |
75 | @-webkit-keyframes bgScroll2 {
76 | 100% {
77 | background-position: -500px 0px;
78 | }
79 | }
80 |
81 | @-moz-keyframes bgScroll2 {
82 | 100% {
83 | background-position: -500px 0px;
84 | }
85 | }
86 |
87 | @-o-keyframes bgScroll2 {
88 | 100% {
89 | background-position: -500px 0px;
90 | }
91 | }
92 |
93 | @-ms-keyframes bgScroll2 {
94 | 100% {
95 | background-position: -500px 0px;
96 | }
97 | }
98 |
99 | @keyframes bgScroll2 {
100 | 100% {
101 | background-position: -500px 0px;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/components/icons/WalletConnectLogoIcon.js:
--------------------------------------------------------------------------------
1 | import { Icon } from "@chakra-ui/core";
2 |
3 | const WalletConnectLogoIcon = (props) => (
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | export default WalletConnectLogoIcon;
14 |
--------------------------------------------------------------------------------
/components/DocHead.js:
--------------------------------------------------------------------------------
1 | import Head from "next/head";
2 |
3 | const description =
4 | "Dark Matter presents: Mission to Marp. Users will navigate their way through a narrative-driven augmented reality game utilizing DeFi yield farming and collectible NFT's. Dark Matter is the next evolution in yield farming protocols.";
5 |
6 | const DocHead = () => (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | {/* og/twitter meta tags below */}
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
35 |
39 |
40 |
41 |
42 | );
43 |
44 | export default DocHead;
45 |
--------------------------------------------------------------------------------
/theme/component-button.js:
--------------------------------------------------------------------------------
1 | const Button = {
2 | variants: {
3 | transparent: {
4 | borderRadius: "lg",
5 | background: "none",
6 | boxShadow: "none",
7 | _hover: {
8 | background: "none",
9 | boxShadow: "none",
10 | },
11 | _focus: {
12 | background: "none",
13 | boxShadow: "none",
14 | },
15 | _active: {
16 | background: "none",
17 | boxShadow: "none",
18 | },
19 | },
20 | "icon-trans": {
21 | background: "none",
22 | borderRadius: "lg",
23 | _hover: {
24 | background: "purple.800",
25 | },
26 | _active: {
27 | background: "purple.800",
28 | },
29 | _focus: {
30 | background: "purple.800",
31 | },
32 | },
33 | primary: {
34 | lineHeight: 6,
35 | textAlign: "center",
36 | fontWeight: "bold",
37 | textTransform: "uppercase",
38 | display: "block",
39 | height: "auto",
40 | border: "none",
41 | minHeight: 0,
42 | padding: "0.625rem 1rem",
43 | borderRadius: "lg",
44 | background: "purple.900",
45 | _hover: {
46 | background: "purple.800",
47 | },
48 | _active: {
49 | background: "purple.800",
50 | },
51 | _focus: {
52 | background: "purple.800",
53 | },
54 | },
55 | "icon-round": {
56 | padding: 4,
57 | height: "auto",
58 | minWidth: 0,
59 | background: "purple.900",
60 | borderRadius: "50%",
61 | _hover: {
62 | background: "purple.800",
63 | },
64 | _active: {
65 | background: "purple.800",
66 | },
67 | _focus: {
68 | background: "purple.800",
69 | },
70 | },
71 | "ghost-matched": {
72 | lineHeight: 6,
73 | textAlign: "center",
74 | fontWeight: "bold",
75 | textTransform: "uppercase",
76 | display: "block",
77 | height: "auto",
78 | border: "none",
79 | minHeight: 0,
80 | padding: "0.625rem 1rem",
81 | borderRadius: "lg",
82 | background: "none",
83 | _hover: {
84 | background: "purple.800",
85 | },
86 | _active: {
87 | background: "purple.800",
88 | },
89 | _focus: {
90 | background: "purple.800",
91 | },
92 | },
93 | },
94 | };
95 |
96 | export default Button;
97 |
--------------------------------------------------------------------------------
/components/story/NFT2.js:
--------------------------------------------------------------------------------
1 | import {
2 | Text,
3 | ModalHeader,
4 | ModalBody,
5 | ModalCloseButton,
6 | useStyleConfig,
7 | Button,
8 | Flex,
9 | VStack,
10 | } from "@chakra-ui/core";
11 |
12 | const NFTStory2 = ({ onGoBack }) => {
13 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
14 | const closeBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
15 |
16 | return (
17 | <>
18 |
26 | LEVEL 2
27 |
28 |
29 |
30 |
31 |
32 | Dark Matter exudes from the altar rock in a half-solid, half-gaseous
33 | form, sliding up and around the Meme Grail, disintegrating it. The
34 | tendril of dark matter then leaps to your right hand. Out of fear in
35 | what you had just witnessed, you fight desperately to retrieve your
36 | hand, but the dark matter holds firm. It coils around your wrist and
37 | digits and then etches—using a portion of itself as ink—a sigil into
38 | your palm. The dark matter returns to the rock and you stare,
39 | dumbfounded, at your throbbing hand.
40 |
41 |
42 | "That symbol on your hand activates the Pineapple Gate, but it
43 | also needs fuel to remain open," Elob says, unphased by what
44 | had just occurred. "When we found the gate, I had some of my
45 | guys tweak it to run by rehypothecating shares of yTSLA. It needs 199
46 | as fuel. You still have your shares of the company, right?"
47 |
48 |
49 | HOLD 199 OF THE SPECIFIED TOKEN TO ACTIVATE AND KEEP OPEN THE
50 | STARGATE
51 |
52 |
53 |
54 |
57 |
58 |
59 | >
60 | );
61 | };
62 |
63 | export default NFTStory2;
64 |
--------------------------------------------------------------------------------
/components/farms/config.js:
--------------------------------------------------------------------------------
1 | import YtslaLogoFull from "../icons/YtslaLogoFull";
2 | import YtslaLogoText from "../icons/YtslaLogoText";
3 | import LogoFullIcon from "../icons/LogoFull";
4 |
5 | /**
6 | * Config object utilised by various farm components per farm.
7 | * Required to reduce the number of non-essential props being passed down the chain.
8 | */
9 | const config = {
10 | yTslaForDMT: {
11 | landingCard: {
12 | titleCopy: "Space Farm",
13 | depositCopy: "Deposit yTSLA",
14 | depositIcon: () => ,
15 | earnCopy: "Earn DMT",
16 | earnIcon: () => ,
17 | tokenPrice1LabelCopy: "yTSLA Price",
18 | tokenPrice2LabelCopy: "DMT Price",
19 | walletConnectBtnCopy: "Unlock Space Wallet",
20 | walletConnectedBtnCopy: "Launch Space Farm",
21 | },
22 | farm: {
23 | titleCopy: "yTSLA Space Farm",
24 | withdrawAllBtnCopy: "Harvest & Withdraw",
25 | },
26 | depositCard: {
27 | titleCopy: "yTSLA",
28 | depositIcon: () => ,
29 | stakedCopy: "yTSLA Staked",
30 | approveBtnCopy: "Approve yTSLA",
31 | },
32 | earnCard: {
33 | titleCopy: "DMT",
34 | earnIcon: () => ,
35 | estimatedCopy: "Estimated DMT earned",
36 | harvestBtnCopy: "Harvest DMT",
37 | },
38 | depositModal: {
39 | openTooltipCopy: "Stake yTSLA",
40 | titleCopy: "Stake yTSLA",
41 | tokenIcon: () => ,
42 | totalRewardsCopy: "Total DMT left to be distributed as rewards",
43 | usersTotalDepositedCopy: "Total yTSLA staked by the community",
44 | userBalanceCopy: "Your yTSLA balance is:",
45 | spinnerMessage: "Staking yTSLA...",
46 | },
47 | withdrawModal: {
48 | openTooltipCopy: "Withdraw yTSLA",
49 | titleCopy: "Withdraw yTSLA",
50 | tokenIcon: () => ,
51 | userTotalDepositedCopy: "Total yTSLA currently staked by you",
52 | usersTotalDepositedCopy: "Total yTSLA staked by the community",
53 | userBalanceCopy: "Your yTSLA balance is:",
54 | spinnerMessage: "Unstaking yTSLA...",
55 | },
56 | },
57 | };
58 |
59 | export default config;
60 |
--------------------------------------------------------------------------------
/components/spinners/Inline.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import PropTypes from "prop-types";
3 |
4 | import _isNull from "lodash/isNull";
5 |
6 | import { Spinner, Flex, Heading } from "@chakra-ui/core";
7 |
8 | let timerFrom = 0;
9 | let timer = null;
10 |
11 | const Inline = ({
12 | isLoading = true,
13 | minSeconds = 1,
14 | spinnerSize = 20,
15 | minHeight = "0",
16 | message = null,
17 | messageSize = "3xl",
18 | children,
19 | }) => {
20 | const [isOpen, setIsOpen] = useState(isLoading);
21 |
22 | useEffect(() => {
23 | if (isLoading && !timerFrom) {
24 | timerFrom = Date.now();
25 |
26 | if (isOpen !== isLoading) setIsOpen(true);
27 | } else if (!isLoading && timerFrom && !timer) {
28 | const timeRemaining = timerFrom + minSeconds * 1000 - Date.now();
29 |
30 | if (timeRemaining >= 0) {
31 | timer = setTimeout(() => close(), timeRemaining);
32 | } else {
33 | close();
34 | }
35 | }
36 | }, [isLoading]);
37 |
38 | useEffect(() => {
39 | return () => clearTimer();
40 | }, []);
41 |
42 | const clearTimer = () => {
43 | if (!_isNull(timer)) {
44 | clearTimeout(timer);
45 |
46 | timer = null;
47 | }
48 | };
49 |
50 | const close = () => {
51 | timerFrom = 0;
52 |
53 | clearTimer();
54 | setIsOpen(false);
55 | };
56 |
57 | return isOpen ? (
58 |
65 |
73 | {message && (
74 |
83 | {message}
84 |
85 | )}
86 |
87 | ) : (
88 | <>{children}>
89 | );
90 | };
91 |
92 | Inline.propTypes = {
93 | isLoading: PropTypes.bool,
94 | minSeconds: PropTypes.number,
95 | spinnerSize: PropTypes.number,
96 | minHeight: PropTypes.string,
97 | message: PropTypes.string,
98 | messageSize: PropTypes.string,
99 | children: PropTypes.node.isRequired,
100 | };
101 |
102 | export default Inline;
103 |
--------------------------------------------------------------------------------
/components/story/NFT4.js:
--------------------------------------------------------------------------------
1 | import {
2 | Text,
3 | ModalHeader,
4 | ModalBody,
5 | ModalCloseButton,
6 | useStyleConfig,
7 | Button,
8 | Flex,
9 | VStack,
10 | } from "@chakra-ui/core";
11 |
12 | const NFTStory4 = ({ onGoBack }) => {
13 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
14 | const closeBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
15 |
16 | return (
17 | <>
18 |
26 | LEVEL 4
27 |
28 |
29 |
30 |
31 |
32 | Soft green lawn appears beneath your feet and you stand in front of
33 | a huge circus tent with red and white stripes. The entrance is
34 | before you and from within a vivid yellow light emanates. Atop the
35 | entrance is a sign that reads:
36 |
37 |
38 | THE ORIGINAL RUG
39 |
40 |
41 | The light is bright and you cannot see what it is inside the tent,
42 | but you hear a very distinct sound coming from within.
43 |
44 |
45 | "Hey, hey, hey. Hey, hey, hey. Wassa, wassa, wassa."
46 |
47 |
48 | An attendant is manning the entrance, saying, "Step right up!
49 | Come and witness the one and only amazing and original rug!"
50 |
51 |
52 | You begin to walk past the circus employee to enter the show, but he
53 | stops you and requests a password. It is not a big deal because you
54 | know exactly what it is. You tell the attendant the password and
55 | walk inside the tent, voyaging to another realm.
56 |
57 |
58 | INPUT THE PASSWORD
59 |
60 |
61 |
62 |
65 |
66 |
67 | >
68 | );
69 | };
70 |
71 | export default NFTStory4;
72 |
--------------------------------------------------------------------------------
/pages/intro.js:
--------------------------------------------------------------------------------
1 | import {
2 | Flex,
3 | Box,
4 | Text,
5 | VStack,
6 | Heading,
7 | } from "@chakra-ui/core";
8 |
9 | import usePageTitle from "../hooks/usePageTitle";
10 |
11 | const Intro = () => {
12 | usePageTitle("Introduction");
13 |
14 | return (
15 |
24 |
25 |
26 | Intro
27 |
28 |
29 |
30 | There is nothing more unsettling than watching someone be positively
31 | rebased by dark matter. Limbs multiply, extra teeth catapult,
32 | screams of agony double with parting vocal chords. The heart beats
33 | until the uncanny network of growth escapes the velocity of ample
34 | circulation. It is a slow and gruesome demise - one that Elob Munk
35 | wishes to never again witness.
36 |
37 |
38 | This renowned CEO of yTSLA had a simple task of initiating the
39 | positive rebase on the Li-ion cells of the batteries being used for
40 | the Marp SpoceX starship fleet. He had performed the task with the
41 | rebase machine successfully many times before, but on this fateful
42 | day his focus was diverted by visions of farming his freshly ripened
43 | pineapple crop. The factor he inputted for the action was
44 | devastatingly high, and, when the rebase initiated, the battery
45 | cells multiplied at far too immense a rate.
46 |
47 |
48 | At this frequency of rebase, the cells began to draw in energy from
49 | across the universe, pulling in dark matter through quantum
50 | entanglement with distant, undesirable galaxies. Elob could feel the
51 | terror gyrating within his moon factory. It was a sense of dread
52 | that built itself within the patterns of his thoughts, impairing
53 | judgment and motor functions. Unable to stop what he had begun, he
54 | witnessed the rebasing dark matter leap from the batteries to his
55 | employees. He flung himself head first into the bulletproof glass
56 | dividing the command room he occupied from his workforce below,
57 | desperate to do anything to reach them. Powerlessly, Elob looked on
58 | as his personnel expunged from his employment, and life.
59 |
60 |
61 |
62 |
63 | );
64 | };
65 |
66 | export default Intro;
67 |
--------------------------------------------------------------------------------
/components/layout/Header.js:
--------------------------------------------------------------------------------
1 | import {
2 | Box,
3 | Flex,
4 | List,
5 | Link,
6 | ListItem,
7 | useStyleConfig,
8 | useBreakpointValue,
9 | } from "@chakra-ui/core";
10 |
11 | import _map from "lodash/map";
12 |
13 | import InternalLink from "../utils/InternalLink";
14 | import LogoLightIcon from "../icons/LogoLight";
15 |
16 | import Drawer from "./Drawer";
17 | import CountdownModal from "../countdown/CountdownModal";
18 | import WalletConnectButton from "../wallet/ConnectButton";
19 |
20 | const Header = () => {
21 | const linkStyles = useStyleConfig("Link", { variant: "nav" });
22 | const shouldRenderDrawer = useBreakpointValue({ base: true, lg: false });
23 |
24 | return (
25 |
26 |
34 | {shouldRenderDrawer && }
35 |
36 |
43 |
44 |
45 | {!shouldRenderDrawer && (
46 |
47 |
48 |
49 | Intro
50 |
51 |
52 |
53 |
54 | Gallery
55 |
56 |
57 |
58 |
59 | Farm
60 |
61 |
62 |
63 |
67 |
68 |
69 |
70 | OpenSea
71 |
72 |
73 |
74 | )}
75 |
80 |
81 |
82 |
83 | );
84 | };
85 |
86 | export default Header;
87 |
--------------------------------------------------------------------------------
/hooks/useContracts.js:
--------------------------------------------------------------------------------
1 | import { useMemo } from "react";
2 | import { useWallet } from "use-wallet";
3 | import { providers as EthersProviders } from "ethers";
4 | import { create as createERC20 } from "../lib/erc20";
5 | import { create as createERC1155 } from "../lib/erc1155";
6 | import { create as createStakingERC20 } from "../lib/stakingERC20";
7 | import { create as createUniswapPair } from "../lib/uniswapPair";
8 | import { create as createStakingERC1155 } from "../lib/stakingERC1155";
9 |
10 | const chains = {
11 | testnet: {
12 | ytslaToken: "0xdDF18785195aFd648c1dEBA4Bf74d0C36D1C0218",
13 | dmtToken: "0xb5D608bB4B3788F84279921FeF171E2d08A74e58",
14 | dmtLtd: "0xaC43eF1686302Fa41434225Eb6a87856017f1A03",
15 | dmtStaking: "0x07E6B7453b474A323aA22789Aa0E92Ab74270762",
16 | nftStaking: "0x8F5d44422A56864FB8Df0602A9D925662c14F0e0",
17 | },
18 | mainnet: {
19 | ytslaToken: "0x5322A3556F979cE2180B30e689a9436fDDCB1021",
20 | dmtToken: "0x79126d32a86e6663F3aAac4527732d0701c1AE6c",
21 | dmtLpToken: "0x2b53861bB489501537CDDF9bFeC8F1cAA2851A24",
22 | dmtLtd: "0x6E91869090a430e6ba6fFa7c585742E56Fed2247",
23 | dmtStaking: "0x550DCE3dEBae1374d0878C5692D52d1ac4b40C5D",
24 | nftStaking: "0x1e54F823De83f84C57e19138850209Ebc7E92d7f",
25 | },
26 | };
27 |
28 | /**
29 | * Switch between the two for testing / production.
30 | */
31 | const addresses = { ...chains.mainnet };
32 |
33 | export function useContracts() {
34 | const { ethereum } = useWallet();
35 | const ethers = useMemo(
36 | () => (ethereum ? new EthersProviders.Web3Provider(ethereum) : null),
37 | [ethereum]
38 | );
39 |
40 | // Single exposed account e.g. MetaMask
41 | const signer = ethers ? ethers.getSigner() : null;
42 |
43 | // yTSLA token
44 | const ytslaToken = addresses.ytslaToken
45 | ? createERC20(addresses.ytslaToken, signer)
46 | : {};
47 |
48 | const ytslaEthPair = addresses.ytslaToken
49 | ? createUniswapPair(addresses.ytslaToken, signer)
50 | : {};
51 |
52 | // DMT token
53 | const dmtToken = addresses.dmtToken
54 | ? createERC20(addresses.dmtToken, signer)
55 | : {};
56 |
57 | const dmtLpToken = addresses.dmtLpToken
58 | ? createERC20(addresses.dmtLpToken, signer)
59 | : {};
60 |
61 | const dmtEthPair = addresses.dmtToken
62 | ? createUniswapPair(addresses.dmtToken, signer)
63 | : {};
64 |
65 | const dmtStaking = addresses.dmtStaking
66 | ? createStakingERC20(addresses.dmtStaking, signer)
67 | : {};
68 |
69 | const dmtLtd = addresses.dmtLtd
70 | ? createERC1155(addresses.dmtLtd, signer)
71 | : {};
72 |
73 | const nftStaking = addresses.nftStaking
74 | ? createStakingERC1155(addresses.nftStaking, signer)
75 | : {};
76 |
77 | return {
78 | ethers,
79 | ytslaToken,
80 | ytslaEthPair,
81 | dmtLtd,
82 | dmtToken,
83 | dmtLpToken,
84 | dmtEthPair,
85 | dmtStaking,
86 | nftStaking,
87 | };
88 | }
89 |
--------------------------------------------------------------------------------
/components/story/NFT3.js:
--------------------------------------------------------------------------------
1 | import {
2 | Text,
3 | ModalHeader,
4 | ModalBody,
5 | ModalCloseButton,
6 | useStyleConfig,
7 | Button,
8 | Flex,
9 | VStack,
10 | } from "@chakra-ui/core";
11 |
12 | const NFTStory3 = ({ onGoBack }) => {
13 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
14 | const closeBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
15 |
16 | return (
17 | <>
18 |
26 | LEVEL 3
27 |
28 |
29 |
30 |
31 |
32 | The stargate activates with a giant whirring sound, blasting
33 | residual dark matter out of the portal like dust on an unused fan.
34 | These airborne particles of aeons-old matter temporarily oscillate
35 | before vanishing into the surroundings.
36 |
37 |
38 | "As long as you hold 199 yTSLA, the stargate will remain
39 | open," Elob says. "Our objective now is to find our new
40 | world." He gestures for you to enter the stargate. You wonder
41 | why you have to lead, but do so anyhow. As you approach the ethereal
42 | dark matter portal, you begin to see the particles moving
43 | independently from each other as if they are all alive, like
44 | fragments of magnets pooled together.
45 |
46 |
47 | You walk into the stargate—the Pineapple Gate.
48 |
49 |
50 | You expect to land on your feet, but you are immediately falling
51 | through infinite space. Stars and cosmic colors brightly light the
52 | void. A Blue Kirby is floating below you and you rub your eyes. It
53 | is really there. As you get closer to the creature, you notice that
54 | it has a tattoo of Andre Cronje with a rug on its cheek. As silly as
55 | it is, you know exactly what to do. You throw a single coin at the
56 | Kirby, it eats it, and then it eats you. You voyage to another
57 | realm.
58 |
59 |
60 | HOLD 1 CORRECT TOKEN TO MOVE TO NEXT LEVEL
61 |
62 |
63 |
64 |
67 |
68 |
69 | >
70 | );
71 | };
72 |
73 | export default NFTStory3;
74 |
--------------------------------------------------------------------------------
/pages/farms/index.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { useRouter } from "next/router";
3 | import { useWallet } from "use-wallet";
4 |
5 | import useInterval from "../../hooks/useInterval";
6 | import { useContracts } from "../../hooks/useContracts";
7 | import { useEthPrice } from "../../hooks/useEthPrice";
8 |
9 | import { isWalletConnected } from "../../lib/wallet";
10 |
11 | import {
12 | Flex,
13 | Box,
14 | Text,
15 | Heading,
16 | } from "@chakra-ui/core";
17 |
18 | import usePageTitle from "../../hooks/usePageTitle";
19 | import FarmLandingCard from "../../components/farms/LandingCard";
20 |
21 | const Index = () => {
22 | const wallet = useWallet();
23 | const { ytslaEthPair, dmtStaking, dmtEthPair } = useContracts();
24 | const { ethUSD } = useEthPrice();
25 |
26 | const router = useRouter();
27 |
28 | const [ytslaPrice, setYtslaPrice] = useState(null);
29 | const [dmtPrice, setDmtPrice] = useState(null);
30 | const [apyAmount, setApyAmount] = useState(null);
31 |
32 | usePageTitle("Space Farms");
33 |
34 | useInterval(() => {
35 | async function updateLiveInfo() {
36 | if (!isWalletConnected(wallet) || !wallet.ethereum) return;
37 |
38 | const rewardPerToken = await dmtStaking.rewardPerToken();
39 | const ytslaPriceETH = await ytslaEthPair.getPrice();
40 | const dmtPriceETH = await dmtEthPair.getPrice();
41 |
42 | const apyValue = rewardPerToken.toNumber() * parseFloat(dmtPriceETH) / Math.pow(10, 18) / parseFloat(ytslaPriceETH) * 86400 * 365 * 100;
43 |
44 | setYtslaPrice(ytslaPriceETH * ethUSD);
45 | setDmtPrice(dmtPriceETH * ethUSD);
46 | setApyAmount(apyValue);
47 | }
48 |
49 | updateLiveInfo().catch(console.log);
50 | }, 2000);
51 |
52 | const handleUnlockWallet = path => () => router.push(path);
53 |
54 | return (
55 |
64 |
65 |
74 | Earn DMT by depositing yTSLA
75 |
76 |
81 |
88 |
89 |
90 |
91 | );
92 | };
93 |
94 | export default Index;
95 |
--------------------------------------------------------------------------------
/components/layout/Drawer.js:
--------------------------------------------------------------------------------
1 | import {
2 | useDisclosure,
3 | useStyleConfig,
4 | IconButton,
5 | Drawer,
6 | DrawerBody,
7 | DrawerHeader,
8 | DrawerOverlay,
9 | DrawerContent,
10 | DrawerCloseButton,
11 | Link,
12 | List,
13 | ListItem,
14 | } from "@chakra-ui/core";
15 |
16 | import { HamburgerIcon } from "@chakra-ui/icons";
17 | import LogoFullIcon from "../icons/LogoFull";
18 |
19 | import InternalLink from "../utils/InternalLink";
20 |
21 | import _map from "lodash/map";
22 |
23 | const placement = "left";
24 |
25 | const DrawerComp = () => {
26 | const { isOpen, onOpen, onClose } = useDisclosure();
27 | const btnStyles = useStyleConfig("Button", { variant: "icon-trans" });
28 | const linkStyles = useStyleConfig("Link", { variant: "drawer-nav" });
29 |
30 | const renderLinksList = () => _map(
31 | [
32 | { to: "/", title: "Home" },
33 | { to: "/intro", title: "Intro" },
34 | { to: "/gallery", title: "Gallery" },
35 | { to: "/farms", title: "Farm" },
36 | { to: "https://opensea.io/collection/dark-matter", title: "OpenSea", isExternal: true, divider: true },
37 | { to: "https://medium.com/@memeytsla", title: "Medium", isExternal: true },
38 | { to: "https://twitter.com/yTSLAFi", title: "Twitter", isExternal: true },
39 | { to: "https://t.me/yTSLA_lounge", title: "Telegram", isExternal: true },
40 | ],
41 | ({ to, title, isExternal, divider }, index, collection) => (
42 |
48 | {!isExternal
49 | ? {title}
50 | : {title}
51 | }
52 |
53 | ),
54 | );
55 |
56 | return (
57 | <>
58 | } onClick={onOpen} />
59 |
69 |
70 |
71 |
72 |
73 |
78 |
79 |
80 | {renderLinksList()}
81 |
82 |
83 |
84 |
85 | >
86 | )
87 | };
88 |
89 | export default DrawerComp;
--------------------------------------------------------------------------------
/components/icons/OpenseaLogoIcon.js:
--------------------------------------------------------------------------------
1 | import { Icon } from "@chakra-ui/core";
2 |
3 | const OpenseaLogoIcon = (props) => (
4 |
5 |
6 |
7 |
8 |
9 |
10 | );
11 |
12 | export default OpenseaLogoIcon;
13 |
--------------------------------------------------------------------------------
/components/icons/YtslaLogoFull.js:
--------------------------------------------------------------------------------
1 | import { Icon } from "@chakra-ui/core";
2 |
3 | const YtslaLogoFull = (props) => (
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 |
18 | export default YtslaLogoFull;
19 |
--------------------------------------------------------------------------------
/components/splash/Splash.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { useRouter } from "next/router";
3 | import _isUndefined from "lodash/isUndefined";
4 |
5 | import { Box, Flex, Image } from "@chakra-ui/core";
6 |
7 | const Splash = () => {
8 | const router = useRouter();
9 | const { asPath } = router;
10 |
11 | const [showLogo, setShowLogo] = useState(false);
12 | const [isOpening, setIsOpening] = useState(false);
13 | const [isComplete, setIsComplete] = useState(false);
14 |
15 | useEffect(() => {
16 | setBodyOverflow("hidden");
17 |
18 | setTimeout(() => {
19 | if (!_isUndefined(showLogo)) setShowLogo(true);
20 | }, 500);
21 |
22 | setTimeout(() => {
23 | if (!_isUndefined(isOpening)) setIsOpening(true);
24 | }, 2500);
25 |
26 | setTimeout(() => {
27 | setBodyOverflow("auto");
28 |
29 |
30 | if(!_isUndefined(isComplete)) setIsComplete(true);
31 | }, 3500);
32 | }, []);
33 |
34 | const setBodyOverflow = (value) => (document.body.style.overflow = value);
35 |
36 | if (asPath !== "/" || isComplete) return null;
37 |
38 | return (
39 |
49 |
50 |
62 |
77 |
78 |
90 |
105 |
106 |
107 |
108 | );
109 | };
110 |
111 | export default Splash;
112 |
--------------------------------------------------------------------------------
/components/layout/Footer.js:
--------------------------------------------------------------------------------
1 | import {
2 | Box,
3 | Flex,
4 | List,
5 | ListItem,
6 | Link,
7 | Icon,
8 | useStyleConfig,
9 | useBreakpointValue,
10 | } from "@chakra-ui/core";
11 |
12 | import { FaMedium, FaTwitter, FaTelegramPlane } from "react-icons/fa";
13 |
14 | import YtslaLogoIcon from "../icons/YtslaLogoIcon";
15 | import EtherscanIcon from "../icons/Etherscan";
16 | import UniswapLogoIcon from "../icons/UniswapLogoIcon";
17 | import OpenseaLogoIcon from "../icons/OpenseaLogoIcon";
18 |
19 | import _map from "lodash/map";
20 |
21 | const linkPaddingConfig = {
22 | default: "0.5625rem 0.5625rem 0.5rem 0.5625rem",
23 | yTSLA: "0.5rem 0.4375rem 0.3125rem 0.4375rem",
24 | uniswap: "0.3125rem 0.4375rem 0.5rem 0.4375rem",
25 | opensea: "0.5625rem 0.5rem 0.4375rem 0.5rem",
26 | };
27 |
28 | const Footer = () => {
29 | const linkIconStyles = useStyleConfig("Link", { variant: "icon-only" });
30 | const showFullFooter = useBreakpointValue({ base: false, sm: true });
31 |
32 | const renderLinksList = () => {
33 | const linksList = _map(
34 | [
35 | { to: "https://medium.com/@memeytsla", title: "Medium", icon: () => },
36 | { to: "https://twitter.com/yTSLAFi", title: "Twitter", icon: () => },
37 | { to: "https://t.me/yTSLA_lounge", title: "Telegram", icon: () => },
38 | { id: "yTSLA", to: "https://www.ytsla.finance/", title: "yTSLA", icon: () => },
39 | { id: "uniswap", to: "https://app.uniswap.org/#/swap?inputCurrency=0x79126d32a86e6663f3aaac4527732d0701c1ae6c&outputCurrency=ETH", title: "Uniswap", icon: () => },
40 | { id: "opensea", to: "https://opensea.io/collection/dark-matter", title: "Dark Matter Ltd OpenSea Marketplace", icon: () => },
41 | { to: "https://etherscan.io/address/0x79126d32a86e6663f3aaac4527732d0701c1ae6c", title: "DMT Contract", icon: () => },
42 | ],
43 | ({ id, to, title, icon: LinkIcon }, index) => {
44 | const linkPadding = linkPaddingConfig[id] || linkPaddingConfig.default;
45 |
46 | return (
47 |
48 |
55 | {}
56 |
57 |
58 | );
59 | }
60 | );
61 |
62 | if (!showFullFooter) linksList.pop();
63 |
64 | return linksList;
65 | };
66 |
67 | return (
68 |
69 |
77 | {renderLinksList()}
78 |
79 |
80 | );
81 | };
82 |
83 | export default Footer;
84 |
--------------------------------------------------------------------------------
/components/farms/EarnCard.js:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types";
2 | import { useWallet } from "use-wallet";
3 |
4 | import { useContracts } from "../../hooks/useContracts";
5 | import { isWalletConnected } from "../../lib/wallet";
6 | import { formatNumber } from "../../lib/numeric";
7 |
8 | import {
9 | Flex,
10 | Box,
11 | Stat,
12 | StatLabel,
13 | StatNumber,
14 | Heading,
15 | Button,
16 | useStyleConfig,
17 | } from "@chakra-ui/core";
18 |
19 | import InlineSpinner from "../spinners/Inline";
20 |
21 | import config from "./config";
22 |
23 | const EarnCard = ({
24 | farmId,
25 | isApproved,
26 | depositAmount,
27 | earnedAmount,
28 | isHarvesting,
29 | setIsHarvesting,
30 | }) => {
31 | const wallet = useWallet();
32 | const { dmtStaking } = useContracts();
33 |
34 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
35 |
36 | const opacity = isApproved && depositAmount ? 1 : 0.2;
37 |
38 | const handleHarvestClick = () => {
39 | if (
40 | !earnedAmount ||
41 | !isWalletConnected(wallet) ||
42 | !wallet.ethereum
43 | ) {
44 | return;
45 | }
46 |
47 | dmtStaking.getReward()
48 | .then(_ => {
49 | setIsHarvesting(true);
50 | })
51 | .catch(_ => {});
52 | };
53 |
54 | const {
55 | titleCopy,
56 | earnIcon: EarnIcon,
57 | estimatedCopy,
58 | harvestBtnCopy,
59 | } = config[farmId].earnCard;
60 |
61 | return (
62 |
63 |
71 |
76 |
84 | {titleCopy}
85 |
86 |
87 |
88 |
89 |
90 | {estimatedCopy}
91 | {formatNumber(earnedAmount, 5)}
92 |
93 |
97 |
105 |
106 |
107 |
108 |
109 | );
110 | };
111 |
112 | EarnCard.propTypes = {
113 | farmId: PropTypes.string.isRequired,
114 | isApproved: PropTypes.bool.isRequired,
115 | depositAmount: PropTypes.number,
116 | earnedAmount: PropTypes.number,
117 | isHarvesting: PropTypes.bool.isRequired,
118 | setIsHarvesting: PropTypes.func.isRequired,
119 | };
120 |
121 | export default EarnCard;
122 |
--------------------------------------------------------------------------------
/components/story/NFT5.js:
--------------------------------------------------------------------------------
1 | import {
2 | Text,
3 | ModalHeader,
4 | ModalBody,
5 | ModalCloseButton,
6 | useStyleConfig,
7 | Button,
8 | Flex,
9 | VStack,
10 | } from "@chakra-ui/core";
11 |
12 | const NFTStory5 = ({ onGoBack }) => {
13 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
14 | const closeBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
15 |
16 | return (
17 | <>
18 |
26 | LEVEL 5
27 |
28 |
29 |
30 |
31 |
32 | Before you are four chefs, and by the ingredients set out before
33 | them—arrays of seaweed, white rice, and brightly-colored raw
34 | fish—you can tell that they are sushi chefs. You sit on a barstool
35 | behind slanted glass that lines the counter of a sushi bar; the
36 | chefs are on the other side. One of the chefs is a panda donning an
37 | apron and hat and is speaking to the other three; you know
38 | immediately that this is the infamous Chef Nomi.
39 |
40 |
41 | "I hope that your craft continues to evolve. Don't let my
42 | mistake deter you from being the 100% best chef you can be. Your
43 | success as a chef will set a precedent for many more chefs."
44 |
45 |
46 | At the conclusion of his words, the other three chefs proceed to
47 | undress Chef Nomi, procure deftly sharpened chef knives, and slice
48 | him up into finely apportioned sheets of flesh. They then take the
49 | Nomi meat—all of it—and meticulously put together several dishes of
50 | bloody panda sushi. You watch in complete shock and disgust.
51 |
52 |
53 | In your mesmerization, you neglect to notice another patron sitting
54 | with you at the bar—it is Sam Bankman-Fried. Together, under a
55 | haunting display of humility and normalcy, the three standing sushi
56 | chefs offer their freshly prepared dishes to Sam. He takes the sushi
57 | and simply says, "Ok uh," before surprisingly going on to
58 | lustfully eat the ensemble of bloody cuisine.
59 |
60 |
61 | Several plates in, you can bear no more of the grotesquery and dash
62 | out of the establishment.
63 |
64 |
65 | When you pass through the doorway, you are not taken to another
66 | realm as you expect. At first, you panic, but then realize why. You
67 | go back inside, quickly retrieve the necessary key, and then exit
68 | again, this time being whisked away to the next dimension.
69 |
70 |
71 | HOLD 1 CORRECT TOKEN TO MOVE TO NEXT LEVEL
72 |
73 |
74 |
75 |
78 |
79 |
80 | >
81 | );
82 | };
83 |
84 | export default NFTStory5;
85 |
--------------------------------------------------------------------------------
/components/gallery/InputPassword.js:
--------------------------------------------------------------------------------
1 | import {
2 | Flex,
3 | Box,
4 | Button,
5 | useStyleConfig,
6 | Modal,
7 | ModalOverlay,
8 | ModalContent,
9 | InputGroup,
10 | Input,
11 | useBreakpointValue,
12 | } from "@chakra-ui/core";
13 | import { useState } from "react";
14 | import FormErrors from "../forms/FormErrors";
15 |
16 | const InputPassword = ({ level, onSuccess, onClose }) => {
17 | const [formErrors, setFormErrors] = useState(null);
18 |
19 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
20 | const cancelBtnStyles = useStyleConfig("Button", {
21 | variant: "ghost-matched",
22 | });
23 |
24 | const isModalCentered = useBreakpointValue({ base: false, md: true });
25 |
26 | const [inputValue, setInputValue] = useState("");
27 |
28 | const checkTokenInputValue = (value) => {
29 | if (value === "") {
30 | setFormErrors(null);
31 |
32 | return false;
33 | }
34 |
35 | const errors = [];
36 |
37 | if (level === "4" && inputValue !== "heyheyhey")
38 | errors.push("Enter the correct password.");
39 |
40 | if (level === "7" && inputValue !== "chucknorris")
41 | errors.push("Enter the correct password.");
42 |
43 | if (errors.length > 0) {
44 | setFormErrors(errors);
45 |
46 | return false;
47 | }
48 |
49 | setFormErrors(null);
50 |
51 | return true;
52 | };
53 |
54 | return (
55 | <>
56 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | {
83 | setInputValue(e.target.value);
84 | }}
85 | onKeyUp={async (e) => {
86 | if (e.keyCode === 13) {
87 | e.preventDefault();
88 | if (checkTokenInputValue(inputValue)) {
89 | await onSuccess();
90 | }
91 | }
92 | }}
93 | />
94 |
95 |
96 |
97 |
98 |
99 |
100 |
113 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | >
123 | );
124 | };
125 |
126 | export default InputPassword;
127 |
--------------------------------------------------------------------------------
/components/farms/LandingCard.js:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types";
2 |
3 | import { formatNumber } from "../../lib/numeric";
4 |
5 | import {
6 | Flex,
7 | Box,
8 | Stat,
9 | StatLabel,
10 | StatNumber,
11 | Text,
12 | Heading,
13 | useBreakpointValue,
14 | } from "@chakra-ui/core";
15 |
16 | import { ArrowRightIcon } from '@chakra-ui/icons';
17 |
18 | import WalletConnectButton from "../wallet/ConnectButton";
19 |
20 | import config from "./config";
21 |
22 | const TokenBox = ({
23 | title,
24 | icon: Icon,
25 | boxPadding,
26 | minWidth,
27 | tokenPriceLabelCopy,
28 | tokenPrice,
29 | }) => (
30 |
31 |
32 |
39 | {title}
40 |
41 |
42 | {tokenPriceLabelCopy}
43 | {formatNumber(tokenPrice, 2, "...", "$")}
44 |
45 |
46 | );
47 |
48 | const LandingCard = ({
49 | farmId,
50 | token1Price,
51 | token2Price,
52 | apyAmount,
53 | onUnlockWallet,
54 | }) => {
55 | const tokenBoxPadding = useBreakpointValue({ base: "1rem", sm: "1.5rem" });
56 |
57 | const {
58 | titleCopy,
59 | depositCopy,
60 | depositIcon,
61 | earnCopy,
62 | earnIcon,
63 | tokenPrice1LabelCopy,
64 | tokenPrice2LabelCopy,
65 | walletConnectBtnCopy,
66 | walletConnectedBtnCopy,
67 | } = config[farmId].landingCard;
68 |
69 | return (
70 |
71 |
79 |
86 | {titleCopy}
87 |
88 |
89 |
97 |
104 |
112 |
113 |
119 | {formatNumber(apyAmount, 2, "...", "", "%")} APY
120 |
121 |
125 |
131 |
132 |
133 |
134 | );
135 | };
136 |
137 | LandingCard.propTypes = {
138 | farmId: PropTypes.oneOf(["yTslaForDMT"]).isRequired,
139 | token1Price: PropTypes.number,
140 | token2Price: PropTypes.number,
141 | apyAmount: PropTypes.number,
142 | onUnlockWallet: PropTypes.func.isRequired,
143 | };
144 |
145 | export default LandingCard;
146 |
--------------------------------------------------------------------------------
/components/gallery/GalleryCard.js:
--------------------------------------------------------------------------------
1 | import { Flex, Box, Button, Text, useStyleConfig } from "@chakra-ui/core";
2 | import { Search2Icon } from "@chakra-ui/icons";
3 |
4 | const CARD_BACK_URL =
5 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AACIl90UuDCLeAG6ct5clfLxa/BLANK.mp4?raw=1";
6 |
7 | const GalleryCard = ({
8 | name,
9 | level,
10 | current,
11 | total,
12 | disabled,
13 | minValueNeeded,
14 | thumbnailUrl = CARD_BACK_URL,
15 | currentCard,
16 | handleUnlock,
17 | onOpen,
18 | setCurrent,
19 | earnedAmount,
20 | }) => {
21 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
22 | const transparentBtnStyles = useStyleConfig("Button", {
23 | variant: "transparent",
24 | });
25 |
26 | return (
27 |
33 |
40 |
70 |
71 |
86 |
87 |
88 |
95 | {current} Minted
96 |
97 |
104 | {total} Total
105 |
106 |
107 |
113 | {name}
114 |
115 |
116 |
135 |
136 |
137 |
138 | );
139 | };
140 |
141 | export default GalleryCard;
142 |
--------------------------------------------------------------------------------
/components/icons/UniswapLogoIcon.js:
--------------------------------------------------------------------------------
1 | import { Icon } from "@chakra-ui/core";
2 |
3 | const UniswapLogoIcon = (props) => (
4 |
5 |
6 |
10 |
15 |
17 |
20 |
24 |
27 |
33 |
41 |
44 |
45 |
46 | );
47 |
48 | export default UniswapLogoIcon;
49 |
--------------------------------------------------------------------------------
/components/icons/MetaMaskLogoIcon.js:
--------------------------------------------------------------------------------
1 | import { Icon } from "@chakra-ui/core";
2 |
3 | const MetaMaskLogoIcon = (props) => (
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 |
41 | export default MetaMaskLogoIcon;
42 |
--------------------------------------------------------------------------------
/components/wallet/WalletModal.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import PropTypes from "prop-types";
3 | import { useWallet } from "use-wallet";
4 |
5 | import {
6 | Box,
7 | Flex,
8 | Button,
9 | Heading,
10 | ModalHeader,
11 | Modal,
12 | ModalOverlay,
13 | ModalContent,
14 | ModalBody,
15 | ModalCloseButton,
16 | useDisclosure,
17 | useStyleConfig,
18 | useBreakpointValue,
19 | } from "@chakra-ui/core";
20 |
21 | import MetaMaskLogoIcon from "../icons/MetaMaskLogoIcon";
22 | import WalletConnectLogoIcon from "../icons/WalletConnectLogoIcon";
23 |
24 | const WalletModal = ({
25 | isModalOpen,
26 | onCloseModal,
27 | }) => {
28 | const wallet = useWallet();
29 | const { isOpen, onOpen, onClose } = useDisclosure();
30 | const closeBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
31 |
32 | const isModalCentered = useBreakpointValue({ base: false, md: true });
33 | const optionsFlexDirection = useBreakpointValue({ base: "column", sm: "row" });
34 | const optionWidth = useBreakpointValue({ base: "100%", sm: "50%" });
35 | const subTitlePadding = useBreakpointValue({ base: 2, sm: 4 });
36 |
37 | useEffect(() => {
38 | if (isModalOpen) {
39 | onOpen();
40 | };
41 | }, []);
42 |
43 | const handleConectClick = connector => () => wallet.connect(connector);
44 |
45 | const handleClose = () => {
46 | onClose();
47 |
48 | onCloseModal();
49 | };
50 |
51 | const WalletOption = ({
52 | title,
53 | subTitle,
54 | icon,
55 | onClick,
56 | }) => (
57 |
58 |
59 |
93 |
94 |
95 | );
96 |
97 | return (
98 |
107 |
108 |
109 |
116 | Unlock Space Wallet
117 |
118 |
119 |
120 |
126 | }
130 | onClick={handleConectClick("injected")}
131 | />
132 | }
136 | onClick={handleConectClick("walletconnect")}
137 | />
138 |
139 |
140 |
141 |
142 |
143 | );
144 | };
145 |
146 | WalletModal.propTypes = {
147 | isModalOpen: PropTypes.bool.isRequired,
148 | onCloseModal: PropTypes.func.isRequired,
149 | };
150 |
151 | export default WalletModal;
152 |
--------------------------------------------------------------------------------
/components/story/NFT6.js:
--------------------------------------------------------------------------------
1 | import {
2 | Text,
3 | ModalHeader,
4 | ModalBody,
5 | ModalCloseButton,
6 | useStyleConfig,
7 | Button,
8 | Flex,
9 | VStack,
10 | } from "@chakra-ui/core";
11 |
12 | const NFTStory6 = ({ onGoBack }) => {
13 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
14 | const closeBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
15 |
16 | return (
17 | <>
18 |
26 | LEVEL 6
27 |
28 |
29 |
30 |
31 |
32 | You arrive under a bright, vivid blue sky. It is all you see.
33 | Seagulls fly above, a light breeze brushes against your face, and
34 | the sound of the ocean tide whispers into your ears. You realize you
35 | are lying down in a hammock at a beach, and you feel at peace for
36 | the first time since entering the Pineapple Gate.
37 |
38 |
39 | After a few moments of basking in the blissful respite, letting your
40 | mind wander from the memories of your voyage, you notice there is a
41 | hole in the hammock beneath your rear-end. Just as you realize this,
42 | someone pokes you in that said region from below. You adjust
43 | yourself in order to see what is there. You are not prepared for the
44 | sight that stains your retinas.
45 |
46 |
47 | John McAfee is lying on the ground, his mouth and nether regions
48 | crusted over with dried blood. When you look upon him, he smiles
49 | with teeth full of blood and penile pulp.
50 |
51 |
52 | It only takes but one glimpse at this nightmarish horror before you
53 | attempt to leap out of the hammock and get as far away as possible.
54 | In your movement—in consequence of the hole and normal complications
55 | in exiting the rope apparatus—you fall flat on top of McAfee. You
56 | scream a deafening plea of repulsion.
57 |
58 |
59 | As you try to get up, McAfee wraps his arms around you and attempts
60 | to hold you down. You fight with all of your might and eventually
61 | free yourself. You then desperately look for a portal to escape this
62 | haunting domain.
63 |
64 |
65 | McAfee laughs at you and you reluctantly turn back towards him.
66 |
67 |
68 | He spits what is left of his severed member at you, which was still
69 | in his mouth. "That’s your ticket," he says, as fresh
70 | blood sloshes from the sides of his mouth. "Hold on tight and
71 | get in the pit." He gestures to a pit that has been dug in the
72 | sand not ten feet away. The depth is around six feet. "Get in
73 | and say goodbye. Oh, and it’s not really an easy decision to make on
74 | your own so I’m not giving you one." McAfee then points an
75 | assault rifle at you.
76 |
77 |
78 | "Don’t forget the special ticket," he says as you almost
79 | pass it by. You pick up what is left of the bloody, mashed organ and
80 | crawl into the pit. "Lay down." You do as told.
81 |
82 |
83 | McAfee starts shoveling sand on top of you. "You might want to
84 | hold your breath," he says while laughing one last time.
85 |
86 |
87 | Trembling with fright, you hold onto McAfee’s zombified privates and
88 | wait for oblivion. As the last shovel of sand falls atop your face,
89 | you are transported away, although the scars of that realm most
90 | certainly remain.
91 |
92 |
93 | HOLD 1 CORRECT TOKEN TO MOVE TO NEXT LEVEL
94 |
95 |
96 |
97 |
100 |
101 |
102 | >
103 | );
104 | };
105 |
106 | export default NFTStory6;
107 |
--------------------------------------------------------------------------------
/components/story/NFT1.js:
--------------------------------------------------------------------------------
1 | import {
2 | Text,
3 | ModalHeader,
4 | ModalBody,
5 | ModalCloseButton,
6 | useStyleConfig,
7 | Button,
8 | Flex,
9 | VStack,
10 | } from "@chakra-ui/core";
11 |
12 | const NFTStory1 = ({ onGoBack }) => {
13 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
14 | const closeBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
15 |
16 | return (
17 | <>
18 |
26 | LEVEL 1
27 |
28 |
29 |
30 |
31 |
32 | You have no idea of what occurred when you stare down at the memo
33 | sent from the SpoceX moon factory, but you sense the urgency.
34 |
35 |
36 | EMERGENCY.
37 |
38 | COME TO THE SPOCEX MOON FACTORY ASAP.
39 |
40 | BRING THE MEME GRAIL.
41 |
42 | THE FATE OF THE UNIVERSE IS IN YOUR HANDS.
43 |
44 | -ELOB
45 |
46 |
47 | In exiting your spacecraft on the SpoceX moon factory landing pad,
48 | the severity of the situation is immediately known as you look upon
49 | Elob’s cracked rind and the dried trickle of yellow juice that had
50 | run down his face to the tips of his brown jacket. In greeting you,
51 | his first words are, "Do you have the grail?" to which you
52 | nod in affirmation, revealing the relic within your possession.
53 |
54 |
55 | The eccentric CEO immediately leads you to a trail that diverges
56 | from the factory and traverses down a steep grade into a moon
57 | crater. During the expedition, Elob recounts the events that
58 | unfolded. The trek outlasts the tale, so for nearly an hour longer,
59 | you listen to the esteemed entrepreneur divulge the secrets of
60 | successful pineapple farming. He speaks of things such as "The
61 | Pineapple Dilemma," but you really do not see how there is a
62 | need to glean such information at such a critical moment in time.
63 |
64 |
65 | Eventually, you are led into an alcove cut into the basin of the
66 | moon crater. Through a brief stint of darkness, you walk blindly
67 | into the unknown. When light returns, you are taken back by what you
68 | find. There is a chamber hundreds of feet high with streaks of
69 | sunlight pushing through thousands of quarter-sized holes in the
70 | ceiling. What these beams of light reveal is stunning.
71 |
72 |
73 | A stargate stands before you and it makes your hair stand on end.The
74 | structure is nearly thirty feet tall and fifty feet wide with a
75 | broad set of stairs ascending to its opening. The inactive portal is
76 | a daunting archway with a framework both mesmerizing and unnerving.
77 | The thick, dark moon rock border looms like a silent stalker,
78 | staring into your soul, ready to carry it endlessly into the stars.
79 | It holds 13 symbols, cut boldly and crisply into the rock as to
80 | present every stroke and detail of one symbol clearly
81 | distinguishable from those of each and every one of the other
82 | symbols.
83 |
84 |
85 | At a distance from the stargate—like the podium of a conductor
86 | before his orchestra—is a huge obelisk of dark moon rock. A winding
87 | staircase wraps around it to where—at its peak—a jagged altar has
88 | been erected.
89 |
90 |
91 | "This," Elob says, gesturing up to the stargate.
92 | "This is how we make things right. We’ll find a parallel world
93 | where yTSLA and SpoceX succeed without the use of the rebase
94 | machine. You must submit the Meme Grail as a sacrifice there on that
95 | altar. Only by doing so can we activate the Pineapple Gate."
96 |
97 |
98 | HOLD THE REQUIRED RELIC TO BEGIN YOUR ADVENTURE
99 |
100 |
101 |
102 |
105 |
106 |
107 | >
108 | );
109 | };
110 |
111 | export default NFTStory1;
112 |
--------------------------------------------------------------------------------
/lib/stakingERC20.js:
--------------------------------------------------------------------------------
1 | import { Contract } from "ethers";
2 |
3 | const abi = [{ "inputs": [{ "internalType": "address", "name": "_rewardsDistribution", "type": "address" }, { "internalType": "address", "name": "_rewardsToken", "type": "address" }, { "internalType": "address", "name": "_stakingToken", "type": "address" }], "payable": false, "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "reward", "type": "uint256" }], "name": "RewardPaid", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "Staked", "type": "event" }, { "anonymous": false, "inputs": [], "name": "Started", "type": "event" }, { "anonymous": false, "inputs": [], "name": "Synced", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "Withdrawn", "type": "event" }, { "constant": true, "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], "name": "balanceOf", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], "name": "earned", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "exit", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [], "name": "getReward", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], "name": "lastRewardPaidTime", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "lastTimeRewardApplicable", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "periodFinish", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "periodStart", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "rewardPerToken", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "rewardRate", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "rewardsDistribution", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "rewardsDuration", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "rewardsToken", "outputs": [{ "internalType": "contract IERC20", "name": "", "type": "address" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "stake", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "stakingToken", "outputs": [{ "internalType": "contract IERC20", "name": "", "type": "address" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "start", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [], "name": "sync", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "totalSupply", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "withdraw", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }];
4 |
5 | export const create = (address, provider) => {
6 | const contract = new Contract(address, abi, provider);
7 |
8 | // READ
9 | const balanceOf = (address) => contract.balanceOf(address);
10 |
11 | const earned = (address) => contract.earned(address);
12 |
13 | const totalSupply = () => contract.totalSupply();
14 |
15 | const rewardPerToken = () => contract.rewardPerToken();
16 |
17 | // WRITE
18 | const stake = (amount) => contract.stake(amount);
19 |
20 | const withdraw = (amount) => contract.withdraw(amount);
21 |
22 | const getReward = () => contract.getReward();
23 |
24 | return {
25 | address,
26 | balanceOf,
27 | earned,
28 | totalSupply,
29 | rewardPerToken,
30 | stake,
31 | withdraw,
32 | getReward
33 | };
34 | }
--------------------------------------------------------------------------------
/components/farms/DepositCard.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import PropTypes from "prop-types";
3 | import { useWallet } from "use-wallet";
4 | import { utils as ethersUtils } from "ethers";
5 | import useInterval from "../../hooks/useInterval";
6 |
7 | import _isUndefined from "lodash/isUndefined";
8 |
9 | import { useContracts } from "../../hooks/useContracts";
10 | import {
11 | isWalletConnected,
12 | getWalletAddress,
13 | } from "../../lib/wallet";
14 | import { formatNumber, isValidNumber } from "../../lib/numeric";
15 |
16 | import {
17 | Flex,
18 | Box,
19 | Stat,
20 | StatLabel,
21 | StatNumber,
22 | Heading,
23 | Button,
24 | useStyleConfig,
25 | } from "@chakra-ui/core";
26 |
27 | import InlineSpinner from "../spinners/Inline";
28 | import DepositOptions from "./DepositOptions";
29 |
30 | import config from "./config";
31 |
32 | const DepositCard = ({
33 | farmId,
34 | onApproveClick,
35 | isApproved,
36 | isApproving,
37 | depositAmount,
38 | isDepositing,
39 | setIsDepositing,
40 | isWithdrawing,
41 | setIsWithdrawing,
42 | }) => {
43 | const wallet = useWallet();
44 | const { ytslaToken, dmtToken, dmtStaking } = useContracts();
45 |
46 | const [userTokenBalance, setUserTokenBalance] = useState(null);
47 | const [totalTokenRewards, setTotalTokenRewards] = useState(null);
48 | const [usersTotalDepositied, setUsersTotalDepositied] = useState(null);
49 |
50 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
51 |
52 | useInterval(() => {
53 | async function updateLiveInfo() {
54 | if (!isWalletConnected(wallet) || !wallet.ethereum) return;
55 |
56 | if (isApproved) {
57 | let liveTokenBalance = await ytslaToken.balanceOf(getWalletAddress(wallet));
58 | let liveTotalTokenRewards = await dmtToken.balanceOf(dmtStaking.address);
59 | let liveUsersTotalDepositied = await dmtStaking.totalSupply();
60 |
61 | /**
62 | * Attempt to convert live values to JS safe numeric.
63 | */
64 | liveTokenBalance = parseFloat(liveTokenBalance);
65 | liveTotalTokenRewards = parseFloat(liveTotalTokenRewards);
66 | liveUsersTotalDepositied = parseFloat(ethersUtils.formatEther(liveUsersTotalDepositied));
67 |
68 | if (!_isUndefined(userTokenBalance)) {
69 | if (liveTokenBalance !== userTokenBalance) setUserTokenBalance(isValidNumber(liveTokenBalance) ? liveTokenBalance : 0);
70 | if (liveTotalTokenRewards !== totalTokenRewards) setTotalTokenRewards(isValidNumber(liveTotalTokenRewards) ? liveTotalTokenRewards : 0);
71 | if (liveUsersTotalDepositied !== usersTotalDepositied) setUsersTotalDepositied(isValidNumber(liveUsersTotalDepositied) ? liveUsersTotalDepositied : 0);
72 | }
73 | }
74 | }
75 |
76 | updateLiveInfo().catch(console.log);
77 | }, 2000);
78 |
79 | const opacity = isApproved ? 1 : 0.2;
80 |
81 | const {
82 | titleCopy,
83 | depositIcon: DepositIcon,
84 | stakedCopy,
85 | approveBtnCopy,
86 | } = config[farmId].depositCard;
87 |
88 | return (
89 |
90 |
98 |
103 |
110 | {titleCopy}
111 |
112 |
113 |
114 |
115 |
116 | {stakedCopy}
117 | {formatNumber(depositAmount, 2)}
118 |
119 | {!isApproved ? (
120 |
121 |
128 |
129 | ) : (
130 |
141 | )}
142 |
143 |
144 |
145 | );
146 | };
147 |
148 | DepositCard.propTypes = {
149 | farmId: PropTypes.string.isRequired,
150 | onApproveClick: PropTypes.func.isRequired,
151 | isApproved: PropTypes.bool.isRequired,
152 | isApproving: PropTypes.bool.isRequired,
153 | depositAmount: PropTypes.number,
154 | isDepositing: PropTypes.bool.isRequired,
155 | setIsDepositing: PropTypes.func.isRequired,
156 | isWithdrawing: PropTypes.bool.isRequired,
157 | setIsWithdrawing: PropTypes.func.isRequired,
158 | };
159 |
160 | export default DepositCard;
161 |
--------------------------------------------------------------------------------
/components/countdown/CountdownModal.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import PropTypes from "prop-types";
3 |
4 | import {
5 | Flex,
6 | Box,
7 | Stat,
8 | Modal,
9 | ModalOverlay,
10 | ModalContent,
11 | ModalHeader,
12 | ModalBody,
13 | ModalCloseButton,
14 | StatLabel,
15 | StatNumber,
16 | IconButton,
17 | useStyleConfig,
18 | useDisclosure,
19 | useBreakpointValue,
20 | } from "@chakra-ui/core";
21 |
22 | import useInterval from "../../hooks/useInterval";
23 |
24 | import { MdTimer } from "react-icons/md";
25 |
26 | const CountdownModal = ({
27 | title,
28 | countTo = "2020-11-02T22:00:00.000Z",
29 | }) => {
30 | const { isOpen, onOpen, onClose } = useDisclosure();
31 |
32 | const iconBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
33 | const isModalCentered = useBreakpointValue({ base: false, md: true });
34 |
35 | const [countHours, setCountHours] = useState(0);
36 | const [countMinutes, setCountMinutes] = useState(0);
37 | const [countSeconds, setCountSeconds] = useState(0);
38 | const [countDelay, setCountDelay] = useState(1000);
39 |
40 | const dateTo = new Date(countTo).getTime();
41 |
42 | useInterval(() => {
43 | /**
44 | * Today's date and time.
45 | */
46 | const dateLocal = new Date();
47 | const dateNow = Date.UTC(dateLocal.getUTCFullYear(), dateLocal.getUTCMonth(), dateLocal.getUTCDate(), dateLocal.getUTCHours(), dateLocal.getUTCMinutes(), dateLocal.getUTCSeconds());
48 |
49 | /**
50 | * Distance between now and the countdown date.
51 | */
52 | const distance = dateTo - dateNow;
53 |
54 | /**
55 | * Calculations hours, minutes, seconds.
56 | */
57 | const hours = Math.floor(distance / 3600000);
58 | const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
59 | const seconds = Math.floor((distance % (1000 * 60)) / 1000);
60 |
61 | if (distance >= 0) {
62 | setCountHours(hours);
63 | setCountMinutes(minutes);
64 | setCountSeconds(seconds);
65 | } else {
66 | /**
67 | * Countdown complete.
68 | */
69 | setCountDelay(null);
70 | }
71 | }, countDelay);
72 |
73 | const prependZero = value => `0${value}`.slice(-2);
74 |
75 | return (
76 | <>
77 | }
85 | />
86 |
95 |
96 |
97 |
105 | {title}
106 |
107 |
108 |
109 |
113 |
123 |
127 |
128 |
129 | HH
130 | {prependZero(countHours)}
131 |
132 |
133 |
134 |
135 | MM
136 | {prependZero(countMinutes)}
137 |
138 |
139 |
140 |
141 | SS
142 | {prependZero(countSeconds)}
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 | >
153 | );
154 | };
155 |
156 | CountdownModal.propTypes = {
157 | title: PropTypes.string.isRequired,
158 | countTo: PropTypes.string.isRequired,
159 | };
160 |
161 | export default CountdownModal;
162 |
--------------------------------------------------------------------------------
/components/wallet/ConnectButton.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import PropTypes from "prop-types";
3 | import { useWallet } from "use-wallet";
4 | import useInterval from "../../hooks/useInterval";
5 |
6 | import { Link, Button, useStyleConfig, Text } from "@chakra-ui/core";
7 |
8 | import _get from "lodash/get";
9 | import _noop from "lodash/noop";
10 | import _isUndefined from "lodash/isUndefined";
11 |
12 | import { formatNumber } from "../../lib/numeric";
13 |
14 | import {
15 | getWalletConnectionStatus,
16 | isWalletDisconnected,
17 | isWalletConnecting,
18 | isWalletConnected,
19 | getWalletAddress,
20 | shortenWalletAddress,
21 | } from "../../lib/wallet";
22 | import { useContracts } from "../../hooks/useContracts";
23 |
24 | import WalletModal from "./WalletModal";
25 |
26 | const ConnectModal = ({
27 | variant,
28 | connectTitle,
29 | connectedTitle,
30 | shouldRenderDrawer,
31 | onConnected = _noop,
32 | }) => {
33 | const wallet = useWallet();
34 | const { dmtToken } = useContracts();
35 |
36 | const [prevConnectionStatus, setPrevConnectionStatus] = useState(getWalletConnectionStatus(wallet));
37 | const [isModalOpen, setIsModalOpen] = useState(false);
38 |
39 | const [userDmtBalance, setUserDmtBalance] = useState(null);
40 |
41 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
42 |
43 | useEffect(() => {
44 | /**
45 | * Disable the modal once the user connects or disconnects their wallet.
46 | */
47 | const currentConnectionStatus = getWalletConnectionStatus(wallet);
48 |
49 | const isNowConnected =
50 | prevConnectionStatus === "disconnected" &&
51 | currentConnectionStatus === "connected";
52 | const isNowDisconnected =
53 | prevConnectionStatus === "connected" &&
54 | currentConnectionStatus === "disconnected";
55 |
56 | if (isNowConnected || isNowDisconnected) {
57 | setPrevConnectionStatus(currentConnectionStatus);
58 |
59 | if (isModalOpen) {
60 | setIsModalOpen(false);
61 | }
62 | }
63 |
64 | /**
65 | * Call wallet connected callback e.g. route change
66 | */
67 | if (isNowConnected) {
68 | // onConnected();
69 | }
70 | });
71 |
72 | useInterval(() => {
73 | async function updateLiveInfo() {
74 | if (!isWalletConnected(wallet) || !wallet.ethereum) return;
75 |
76 | /**
77 | * Update live DMT balance.
78 | */
79 | const liveDmtBalance = await dmtToken.balanceOf(getWalletAddress(wallet));
80 |
81 | if (!_isUndefined(userDmtBalance) && liveDmtBalance !== userDmtBalance) setUserDmtBalance(liveDmtBalance);
82 | }
83 |
84 | updateLiveInfo().catch(console.log);
85 | }, 2000);
86 |
87 | const handleOpenModal = () => setIsModalOpen(true);
88 |
89 | const handleCloseModal = () => setIsModalOpen(false);
90 |
91 | if (variant === "headerNav") {
92 | if (isWalletDisconnected(wallet) || isWalletConnecting(wallet)) {
93 | /**
94 | * Show "Wallet Connect" button.
95 | */
96 | return (
97 | <>
98 |
101 | {isModalOpen && (
102 |
103 | )}
104 | >
105 | );
106 | } else if (isWalletConnected(wallet)) {
107 | /**
108 | * Show wallet address.
109 | */
110 | const walletAddress = getWalletAddress(wallet);
111 |
112 | if (walletAddress) {
113 | return (
114 |
129 |
135 | {formatNumber(userDmtBalance, 5)} DMT
136 |
137 | {!shouldRenderDrawer && (
138 |
146 | {shortenWalletAddress(walletAddress)}
147 |
148 | )}
149 |
150 | );
151 | }
152 | }
153 | } else if (variant === "card") {
154 | if (isWalletDisconnected(wallet) || isWalletConnecting(wallet)) {
155 | /**
156 | * Show "Wallet Connect" button.
157 | */
158 | return (
159 | <>
160 |
163 | {isModalOpen && (
164 |
165 | )}
166 | >
167 | );
168 | } else if (isWalletConnected(wallet)) {
169 | /**
170 | * Show "Continue" link.
171 | */
172 | return (
173 |
176 | );
177 | }
178 | }
179 |
180 | return null;
181 | };
182 |
183 | ConnectModal.propTypes = {
184 | variant: PropTypes.oneOf(["headerNav", "card"]).isRequired,
185 | connectTitle: PropTypes.string.isRequired,
186 | connectedTitle: PropTypes.string,
187 | onConnected: PropTypes.func,
188 | };
189 |
190 | export default ConnectModal;
191 |
--------------------------------------------------------------------------------
/components/story/NFT7.js:
--------------------------------------------------------------------------------
1 | import {
2 | Text,
3 | ModalHeader,
4 | ModalBody,
5 | ModalCloseButton,
6 | useStyleConfig,
7 | Button,
8 | Flex,
9 | VStack,
10 | } from "@chakra-ui/core";
11 |
12 | const NFTStory7 = ({ onGoBack }) => {
13 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
14 | const closeBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
15 |
16 | return (
17 | <>
18 |
26 | LEVEL 7
27 |
28 |
29 |
30 |
31 |
32 | Finally your twisted adventure appears to have come to a conclusion
33 | and you arrive back in front of the Pineapple Gate on the moon. You
34 | make a huge sigh of relief, but at the tail end of what should have
35 | been a relaxing breath, you realize something odd and rather
36 | disturbing.{" "}
37 |
38 | Never once in any of the realms did you see Elob Munk! Where was
39 | he?
40 |
41 |
42 |
43 | Your breaths become shallow. You do not know whether to feel angry
44 | or scared. As you try to collect your thoughts, you see footprints
45 | leading away from the Pineapple Gate and its stairs.{" "}
46 | It has to be Elob, you think to yourself.
47 |
48 |
49 | Now filled with an ounce of hope, you follow the footprints back to
50 | the SpoceX moon factory. When you get there, after the lengthy hike,
51 | you see that you have arrived in an alternate universe where the
52 | factory is still operational and the workers have not been rebased
53 | to hell.
54 |
55 |
56 | You sneak into the factory and spot Elob in the command room, but
57 | you do not know whether it is your Elob or this world’s Elob. As you
58 | get closer, another Elob enters the room behind the first Elob! Both
59 | Elobs are wearing the same outfit, but this new Elob is wielding a
60 | curved pineapple knife. You can also just barely make out the crack
61 | on the entering Elob’s rind.
62 |
63 |
64 | With one quick stab into the back of the head, the stealth Elob
65 | takes out the incumbent CEO. No one notices but you. You gasp
66 | quietly to yourself, and ponder on your own double’s whereabouts.
67 |
68 |
69 | You quickly make your way to the command room and avoid contact with
70 | any of the employees, especially those you recognize and who could
71 | very well recognize you. You open the door and slide inside.
72 |
73 |
74 | "Elob!" you say, joyfully. As Elob turns to face you, you
75 | realize something is terribly wrong. This is not the Elob from your
76 | world. While the crack in the rind is in the same place, there is
77 | dark matter pulsating in and from the wound. You notice that the
78 | sigil on your hand also begins to pulsate. He gives you the side eye like a Texas ranger.
79 |
80 |
81 | "You left me there to die," he says, confusing you with your own counterpart from his world, "while the dark matter entered me and began rebasing my thoughts with the force of delta. It has given me such awful visions—visions that pull and press and rip at your very being—but these visions also give truth that ravishes all desire. This truth leaves you with nothing, nothing but a craving for expansion—creation upon creation into the darkness of endless life. Join me on my quest to Marp—to the cradle of dark futures where we can release enough dark matter to rebase the entire universe!"
82 |
83 |
84 | "Duck!" You turn from Altered Elob and see your own Elob
85 | enter the command room. You immediately fall to the floor, and over
86 | you sails a large stainless steel pineapple parer that squarely
87 | smacks the villainous Elob on his pineapple head. You wonder whether
88 | to be more scared of Altered Elob or the fact that your Elob somehow
89 | had a pineapple parer that is strictly used for pineapple lobotomies
90 | and cannibalism.
91 |
92 |
93 | Altered Elob screams. You hear the crack in his rind begin to widen,
94 | and you see the dark matter within begin to lunge outward in
95 | tendrils of congealed particles. You watch as the twisted substance
96 | breaks his bones, sucks in his flesh, and negatively rebases him
97 | into nothing. But, what shocks you the most, is that briefly—just
98 | before his head twists and is sucked into his spine—you see the face
99 | of a certain individual beneath his decomposing rind staring
100 | directly at you with staggering solemnity. Before you have time to
101 | process this discovery, the thing—formerly known as Altered Elob—is
102 | erased from the room along with the dark matter he carried.
103 |
104 |
105 | You look up at your Elob.{" "}
106 |
107 | Could it really be him in my world as well?
108 | {" "}
109 | you ask yourself, thinking of the incognito champion hidden beneath
110 | his hard shell head and green top hair. Elob walks over to where his
111 | evil double once was and picks up one last speck of dark matter that
112 | remains. He then speaks about going to Marp and stopping the dark matter once and for all. At the conclusion of his declamation, he expresses a phrase that confirms your suspicions about him.
113 |
114 |
115 | "My kind of trouble doesn’t take vacations."
116 |
117 |
118 | INPUT THE NAME OF ELOB’S HIDDEN ALIAS TO COMPLETE THE ADVENTURE
119 |
120 |
121 |
122 |
125 |
126 |
127 | >
128 | );
129 | };
130 |
131 | export default NFTStory7;
132 |
--------------------------------------------------------------------------------
/pages/api/nft/[id].js:
--------------------------------------------------------------------------------
1 | const nftList = [
2 | {
3 | external_url: "https://darkmatter.finance/gallery",
4 | image:
5 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAA21HvrZgXkZ8HIWDYL2kKOa/DMT_1.png?raw=1",
6 | animation_url:
7 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AABXvXyTZgB9jASiNVHH46Zoa/DMT_1.mp4?raw=1",
8 | name: "Pineapple Gate",
9 | description: "The gateway to all Dark Matter adventures.",
10 | attributes: [
11 | {
12 | trait_type: "Set",
13 | value: "Dark Matter Origins",
14 | },
15 | {
16 | trait_type: "Artist",
17 | value: "Pings",
18 | },
19 | {
20 | trait_type: "Set Number",
21 | value: "1 of 7",
22 | },
23 | {
24 | trait_type: "Tag",
25 | value: "DMT",
26 | },
27 | {
28 | trait_type: "Max Supply",
29 | value: "99",
30 | },
31 | ],
32 | },
33 | {
34 | external_url: "https://darkmatter.finance/gallery",
35 | image:
36 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAC_sH-Zs6eQgzzg_AcI19u9a/DMT_2.png?raw=1",
37 | animation_url:
38 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAC2YeY40K1U8PkZXuaK-9Bua/DMT_2.mp4?raw=1",
39 | name: "Cosmic Fuel",
40 | description: "No fuel, no future. or - No fuel, no future, no fun.",
41 | attributes: [
42 | {
43 | trait_type: "Set",
44 | value: "Dark Matter Origins",
45 | },
46 | {
47 | trait_type: "Artist",
48 | value: "Pings",
49 | },
50 | {
51 | trait_type: "Set Number",
52 | value: "2 of 7",
53 | },
54 | {
55 | trait_type: "Tag",
56 | value: "DMT",
57 | },
58 | {
59 | trait_type: "Max Supply",
60 | value: "99",
61 | },
62 | ],
63 | },
64 | {
65 | external_url: "https://darkmatter.finance/gallery",
66 | image:
67 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAAciZt3ASD3I30kqG5_gj0_a/DMT_3.png?raw=1",
68 | animation_url:
69 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAD4X1giMZlsI_MUBP_owSU6a/DMT_3.mp4?raw=1",
70 | name: "Rug in Prod",
71 | description: "Rugging is eminence... er, imminent.",
72 | attributes: [
73 | {
74 | trait_type: "Set",
75 | value: "Dark Matter Origins",
76 | },
77 | {
78 | trait_type: "Artist",
79 | value: "Pings",
80 | },
81 | {
82 | trait_type: "Set Number",
83 | value: "3 of 7",
84 | },
85 | {
86 | trait_type: "Tag",
87 | value: "DMT",
88 | },
89 | {
90 | trait_type: "Max Supply",
91 | value: "99",
92 | },
93 | ],
94 | },
95 | {
96 | external_url: "https://darkmatter.finance/gallery",
97 | image:
98 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AABVbZux7KELgprYfC5TmgpPa/DMT_4.png?raw=1",
99 | animation_url:
100 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AACF30g4PvM3ewjWu1Q32n6ca/DMT_4.mp4?raw=1",
101 | name: "Proof of Ponzi",
102 | description: "The Original Rug. (Good!)",
103 | attributes: [
104 | {
105 | trait_type: "Set",
106 | value: "Dark Matter Origins",
107 | },
108 | {
109 | trait_type: "Artist",
110 | value: "Pings",
111 | },
112 | {
113 | trait_type: "Set Number",
114 | value: "4 of 7",
115 | },
116 | {
117 | trait_type: "Tag",
118 | value: "DMT",
119 | },
120 | {
121 | trait_type: "Max Supply",
122 | value: "99",
123 | },
124 | ],
125 | },
126 | {
127 | external_url: "https://darkmatter.finance/gallery",
128 | image:
129 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAADwJhB2D8e_FO7uwyPckqca/DMT_5.png?raw=1",
130 | animation_url:
131 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AADGKGpkGBDK8e1AFCi3bDb4a/DMT_5.mp4?raw=1",
132 | name: "Bloody Sushi",
133 | description: "You are what you eat.",
134 | attributes: [
135 | {
136 | trait_type: "Set",
137 | value: "Dark Matter Origins",
138 | },
139 | {
140 | trait_type: "Artist",
141 | value: "Pings",
142 | },
143 | {
144 | trait_type: "Set Number",
145 | value: "5 of 7",
146 | },
147 | {
148 | trait_type: "Tag",
149 | value: "DMT",
150 | },
151 | {
152 | trait_type: "Max Supply",
153 | value: "99",
154 | },
155 | ],
156 | },
157 | {
158 | external_url: "https://darkmatter.finance/gallery",
159 | image:
160 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AADEc9XSdl66gx3ltca4i2y-a/DMT_6.png?raw=1",
161 | animation_url:
162 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AABWLf9qAG0yuipHqy4LY-6na/DMT_6.mp4?raw=1",
163 | name: "Masochist Munchies",
164 | description: "When bet turns into bite.",
165 | attributes: [
166 | {
167 | trait_type: "Set",
168 | value: "Dark Matter Origins",
169 | },
170 | {
171 | trait_type: "Artist",
172 | value: "Pings",
173 | },
174 | {
175 | trait_type: "Set Number",
176 | value: "6 of 7",
177 | },
178 | {
179 | trait_type: "Tag",
180 | value: "DMT",
181 | },
182 | {
183 | trait_type: "Max Supply",
184 | value: "99",
185 | },
186 | ],
187 | },
188 | {
189 | external_url: "https://darkmatter.finance/gallery",
190 | image:
191 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAAgRth6Uwu56_QIRDoiXh-7a/DMT_7.png?raw=1",
192 | animation_url:
193 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAAv6JVLHHxdeYAyM51Ryub_a/DMT_7.mp4?raw=1",
194 | name: "Daddy's Home",
195 | description:
196 | "I'm holdin' out for a hero 'til the end of the night. He's gotta be strong, And he's gotta be fast, And he's gotta be fresh from the fight.",
197 | attributes: [
198 | {
199 | trait_type: "Set",
200 | value: "Dark Matter Origins",
201 | },
202 | {
203 | trait_type: "Artist",
204 | value: "Pings",
205 | },
206 | {
207 | trait_type: "Set Number",
208 | value: "7 of 7",
209 | },
210 | {
211 | trait_type: "Tag",
212 | value: "DMT",
213 | },
214 | {
215 | trait_type: "Max Supply",
216 | value: "99",
217 | },
218 | ],
219 | },
220 | {
221 | external_url: "https://darkmatter.finance/gallery",
222 | image:
223 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AADA-8Tg18lSgNSubxebrjt7a/DMT_8.png?raw=1",
224 | animation_url:
225 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AADeMva6tjAE1i6gv3rkMFOfa/DMT_8.mp4?raw=1",
226 | name: "Munky in the Middle",
227 | description:
228 | "Limited seating available. First come, first served. No reservations.",
229 | attributes: [
230 | {
231 | trait_type: "Set",
232 | value: "Dark Matter Origins",
233 | },
234 | {
235 | trait_type: "Artist",
236 | value: "Pings",
237 | },
238 | {
239 | trait_type: "Tag",
240 | value: "DMT",
241 | },
242 | {
243 | trait_type: "Max Supply",
244 | value: "99",
245 | },
246 | ],
247 | },
248 | ];
249 |
250 | const handleRequest = (req, res) => {
251 | const nft = nftList[req.query.id - 1];
252 |
253 | if (nft) res.json(nft);
254 |
255 | res.statusCode = 400;
256 | res.end("Could not find NFT...");
257 | };
258 |
259 | export default handleRequest;
260 |
--------------------------------------------------------------------------------
/lib/stakingERC1155.js:
--------------------------------------------------------------------------------
1 | import { Contract, utils } from "ethers";
2 |
3 | const abi = [
4 | {
5 | inputs: [
6 | {
7 | internalType: "contract ERC1155Tradable",
8 | name: "_memesAddress",
9 | type: "address",
10 | },
11 | {
12 | internalType: "contract IERC20",
13 | name: "_memeAddress",
14 | type: "address",
15 | },
16 | ],
17 | payable: false,
18 | stateMutability: "nonpayable",
19 | type: "constructor",
20 | },
21 | {
22 | anonymous: false,
23 | inputs: [
24 | {
25 | indexed: false,
26 | internalType: "uint256",
27 | name: "card",
28 | type: "uint256",
29 | },
30 | {
31 | indexed: false,
32 | internalType: "uint256",
33 | name: "points",
34 | type: "uint256",
35 | },
36 | ],
37 | name: "CardAdded",
38 | type: "event",
39 | },
40 | {
41 | anonymous: false,
42 | inputs: [
43 | {
44 | indexed: true,
45 | internalType: "address",
46 | name: "previousOwner",
47 | type: "address",
48 | },
49 | {
50 | indexed: true,
51 | internalType: "address",
52 | name: "newOwner",
53 | type: "address",
54 | },
55 | ],
56 | name: "OwnershipTransferred",
57 | type: "event",
58 | },
59 | {
60 | anonymous: false,
61 | inputs: [
62 | { indexed: true, internalType: "address", name: "user", type: "address" },
63 | {
64 | indexed: false,
65 | internalType: "uint256",
66 | name: "amount",
67 | type: "uint256",
68 | },
69 | ],
70 | name: "Redeemed",
71 | type: "event",
72 | },
73 | {
74 | anonymous: false,
75 | inputs: [
76 | { indexed: true, internalType: "address", name: "user", type: "address" },
77 | {
78 | indexed: false,
79 | internalType: "uint256",
80 | name: "amount",
81 | type: "uint256",
82 | },
83 | ],
84 | name: "Staked",
85 | type: "event",
86 | },
87 | {
88 | anonymous: false,
89 | inputs: [
90 | { indexed: true, internalType: "address", name: "user", type: "address" },
91 | {
92 | indexed: false,
93 | internalType: "uint256",
94 | name: "amount",
95 | type: "uint256",
96 | },
97 | ],
98 | name: "Withdrawn",
99 | type: "event",
100 | },
101 | {
102 | constant: false,
103 | inputs: [
104 | { internalType: "uint256", name: "cardId", type: "uint256" },
105 | { internalType: "uint256", name: "amount", type: "uint256" },
106 | ],
107 | name: "addCard",
108 | outputs: [],
109 | payable: false,
110 | stateMutability: "nonpayable",
111 | type: "function",
112 | },
113 | {
114 | constant: true,
115 | inputs: [{ internalType: "address", name: "account", type: "address" }],
116 | name: "balanceOf",
117 | outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
118 | payable: false,
119 | stateMutability: "view",
120 | type: "function",
121 | },
122 | {
123 | constant: true,
124 | inputs: [{ internalType: "uint256", name: "", type: "uint256" }],
125 | name: "cards",
126 | outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
127 | payable: false,
128 | stateMutability: "view",
129 | type: "function",
130 | },
131 | {
132 | constant: true,
133 | inputs: [{ internalType: "address", name: "account", type: "address" }],
134 | name: "earned",
135 | outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
136 | payable: false,
137 | stateMutability: "view",
138 | type: "function",
139 | },
140 | {
141 | constant: false,
142 | inputs: [],
143 | name: "exit",
144 | outputs: [],
145 | payable: false,
146 | stateMutability: "nonpayable",
147 | type: "function",
148 | },
149 | {
150 | constant: true,
151 | inputs: [],
152 | name: "isOwner",
153 | outputs: [{ internalType: "bool", name: "", type: "bool" }],
154 | payable: false,
155 | stateMutability: "view",
156 | type: "function",
157 | },
158 | {
159 | constant: true,
160 | inputs: [{ internalType: "address", name: "", type: "address" }],
161 | name: "lastUpdateTime",
162 | outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
163 | payable: false,
164 | stateMutability: "view",
165 | type: "function",
166 | },
167 | {
168 | constant: true,
169 | inputs: [],
170 | name: "meme",
171 | outputs: [{ internalType: "contract IERC20", name: "", type: "address" }],
172 | payable: false,
173 | stateMutability: "view",
174 | type: "function",
175 | },
176 | {
177 | constant: true,
178 | inputs: [],
179 | name: "memes",
180 | outputs: [
181 | { internalType: "contract ERC1155Tradable", name: "", type: "address" },
182 | ],
183 | payable: false,
184 | stateMutability: "view",
185 | type: "function",
186 | },
187 | {
188 | constant: true,
189 | inputs: [],
190 | name: "owner",
191 | outputs: [{ internalType: "address", name: "", type: "address" }],
192 | payable: false,
193 | stateMutability: "view",
194 | type: "function",
195 | },
196 | {
197 | constant: true,
198 | inputs: [{ internalType: "address", name: "", type: "address" }],
199 | name: "points",
200 | outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
201 | payable: false,
202 | stateMutability: "view",
203 | type: "function",
204 | },
205 | {
206 | constant: false,
207 | inputs: [{ internalType: "uint256", name: "card", type: "uint256" }],
208 | name: "redeem",
209 | outputs: [],
210 | payable: false,
211 | stateMutability: "nonpayable",
212 | type: "function",
213 | },
214 | {
215 | constant: false,
216 | inputs: [],
217 | name: "renounceOwnership",
218 | outputs: [],
219 | payable: false,
220 | stateMutability: "nonpayable",
221 | type: "function",
222 | },
223 | {
224 | constant: false,
225 | inputs: [{ internalType: "uint256", name: "amount", type: "uint256" }],
226 | name: "stake",
227 | outputs: [],
228 | payable: false,
229 | stateMutability: "nonpayable",
230 | type: "function",
231 | },
232 | {
233 | constant: true,
234 | inputs: [],
235 | name: "totalSupply",
236 | outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
237 | payable: false,
238 | stateMutability: "view",
239 | type: "function",
240 | },
241 | {
242 | constant: false,
243 | inputs: [{ internalType: "address", name: "newOwner", type: "address" }],
244 | name: "transferOwnership",
245 | outputs: [],
246 | payable: false,
247 | stateMutability: "nonpayable",
248 | type: "function",
249 | },
250 | {
251 | constant: false,
252 | inputs: [{ internalType: "uint256", name: "amount", type: "uint256" }],
253 | name: "withdraw",
254 | outputs: [],
255 | payable: false,
256 | stateMutability: "nonpayable",
257 | type: "function",
258 | },
259 | ];
260 |
261 | export const create = (address, provider) => {
262 | const contract = new Contract(address, abi, provider);
263 |
264 | // READ
265 | const balanceOf = (address) =>
266 | contract.balanceOf(address).then(utils.formatEther);
267 |
268 | const cards = (input) =>
269 | contract.cards(input).then((v) => parseInt(utils.formatEther(v)));
270 |
271 | const earned = (address) =>
272 | contract.earned(address).then(utils.formatEther).then(parseFloat);
273 |
274 | const points = (address) =>
275 | contract.points(address).then(utils.formatEther).then(parseFloat);
276 |
277 | // WRITE
278 | const stake = (amount) => contract.stake(amount);
279 |
280 | const redeem = (card) => contract.redeem(card);
281 |
282 | const withdraw = (amount) => contract.withdraw(amount);
283 |
284 | return {
285 | address,
286 | balanceOf,
287 | cards,
288 | earned,
289 | points,
290 | stake,
291 | redeem,
292 | withdraw,
293 | };
294 | };
295 |
--------------------------------------------------------------------------------
/components/farms/DepositModal.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import PropTypes from "prop-types";
3 | import { useWallet } from "use-wallet";
4 | import { utils as ethersUtils } from "ethers";
5 |
6 | import _get from "lodash/get";
7 | import _size from "lodash/size";
8 | import _trim from "lodash/trim";
9 | import _isUndefined from "lodash/isUndefined";
10 |
11 | import { useContracts } from "../../hooks/useContracts";
12 |
13 | import { isWalletConnected } from "../../lib/wallet";
14 |
15 | import { formatNumber, isValidNumber } from "../../lib/numeric";
16 | import usePrevious from "../../hooks/usePrevious";
17 |
18 | import {
19 | Box,
20 | Flex,
21 | Text,
22 | Button,
23 | IconButton,
24 | Modal,
25 | ModalOverlay,
26 | ModalContent,
27 | ModalHeader,
28 | ModalFooter,
29 | ModalBody,
30 | ModalCloseButton,
31 | Stat,
32 | StatLabel,
33 | StatNumber,
34 | Input,
35 | InputGroup,
36 | InputRightElement,
37 | Tooltip,
38 | useDisclosure,
39 | useStyleConfig,
40 | useBreakpointValue,
41 | } from "@chakra-ui/core";
42 |
43 | import { AddIcon } from "@chakra-ui/icons";
44 |
45 | import InlineSpinner from "../spinners/Inline";
46 | import FormErrors from "../forms/FormErrors";
47 |
48 | import config from "./config";
49 |
50 | const DepositModal = ({
51 | farmId,
52 | userTokenBalance,
53 | isDepositing,
54 | setIsDepositing,
55 | totalTokenRewards,
56 | usersTotalDepositied,
57 | }) => {
58 | const wallet = useWallet();
59 | const { dmtStaking } = useContracts();
60 |
61 | const [tokenInputValue, setTokenInputValue] = useState("");
62 | const prevIsDepositing = usePrevious(!isDepositing ? false : true);
63 |
64 | const { isOpen, onOpen, onClose } = useDisclosure();
65 |
66 | const closeBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
67 | const depositBtnStyles = useStyleConfig("Button", { variant: "icon-round" });
68 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
69 | const cancelBtnStyles = useStyleConfig("Button", { variant: "ghost-matched" });
70 |
71 | const isModalCentered = useBreakpointValue({ base: false, md: true });
72 |
73 | const [formErrors, setFormErrors] = useState(null);
74 |
75 | /**
76 | * Close modal once deposit transaction completes (previous deposit amount !== latest deposit amount).
77 | */
78 | useEffect(() => {
79 | if (prevIsDepositing && !isDepositing) onClose();
80 | }, [isDepositing]);
81 |
82 | const handleTokenInputChange = event => {
83 | const value = _get(event, "target.value");
84 |
85 | checkTokenInputValue(value);
86 |
87 | setTokenInputValue(value);
88 | };
89 |
90 | const handleMaxValueClick = () => {
91 | checkTokenInputValue(userTokenBalance);
92 |
93 | setTokenInputValue(userTokenBalance);
94 | };
95 |
96 | const handleDepositClick = () => {
97 | const formattedValue = _trim(tokenInputValue.toString());
98 |
99 | if (
100 | !checkTokenInputValue(tokenInputValue) ||
101 | !formattedValue ||
102 | !isWalletConnected(wallet) ||
103 | !wallet.ethereum
104 | ) {
105 | return;
106 | }
107 |
108 | dmtStaking.stake(ethersUtils.parseEther(formattedValue))
109 | .then(_ => {
110 | setTokenInputValue("");
111 |
112 | setIsDepositing(true);
113 | })
114 | .catch(_ => {});
115 | };
116 |
117 | const checkTokenInputValue = value => {
118 | if (value === "") {
119 | setFormErrors(null);
120 |
121 | return false;
122 | }
123 |
124 | const errors = [];
125 |
126 | if (!isValidNumber(value, 0.1, userTokenBalance)) errors.push("Enter a valid amount.");
127 |
128 | if (_size(errors)) {
129 | setFormErrors(errors);
130 |
131 | return false;
132 | }
133 |
134 | setFormErrors(null);
135 |
136 | return true;
137 | };
138 |
139 | const {
140 | openTooltipCopy,
141 | titleCopy,
142 | tokenIcon: TokenIcon,
143 | totalRewardsCopy,
144 | usersTotalDepositedCopy,
145 | userBalanceCopy,
146 | spinnerMessage,
147 | } = config[farmId].depositModal;
148 |
149 | return (
150 | <>
151 |
161 | }
167 | />
168 |
169 |
178 |
179 |
180 |
188 | {titleCopy}
189 |
190 |
191 |
192 |
193 |
194 |
195 |
200 |
201 |
202 |
203 | {totalRewardsCopy}
204 | {formatNumber(totalTokenRewards, 4)}
205 |
206 |
207 |
208 |
209 | {usersTotalDepositedCopy}
210 | {formatNumber(usersTotalDepositied)}
211 |
212 |
213 |
214 |
215 | {userBalanceCopy} {formatNumber(userTokenBalance)}
216 |
217 |
218 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 | >
261 | );
262 | };
263 |
264 | DepositModal.propTypes = {
265 | farmId: PropTypes.string.isRequired,
266 | userTokenBalance: PropTypes.number,
267 | isDepositing: PropTypes.bool.isRequired,
268 | setIsDepositing: PropTypes.func.isRequired,
269 | totalTokenRewards: PropTypes.number,
270 | usersTotalDepositied: PropTypes.number,
271 | };
272 |
273 | export default DepositModal;
274 |
--------------------------------------------------------------------------------
/components/farms/WithdrawModal.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import PropTypes from "prop-types";
3 | import { useWallet } from "use-wallet";
4 | import { utils as ethersUtils } from "ethers";
5 |
6 | import _get from "lodash/get";
7 | import _size from "lodash/size";
8 | import _trim from "lodash/trim";
9 | import _isUndefined from "lodash/isUndefined";
10 |
11 | import { useContracts } from "../../hooks/useContracts";
12 |
13 | import { isWalletConnected } from "../../lib/wallet";
14 |
15 | import { formatNumber, isValidNumber } from "../../lib/numeric";
16 | import usePrevious from "../../hooks/usePrevious";
17 |
18 | import {
19 | Box,
20 | Flex,
21 | Text,
22 | Button,
23 | IconButton,
24 | Modal,
25 | ModalOverlay,
26 | ModalContent,
27 | ModalHeader,
28 | ModalFooter,
29 | ModalBody,
30 | ModalCloseButton,
31 | Stat,
32 | StatLabel,
33 | StatNumber,
34 | Input,
35 | InputGroup,
36 | InputRightElement,
37 | Tooltip,
38 | useDisclosure,
39 | useStyleConfig,
40 | useBreakpointValue,
41 | } from "@chakra-ui/core";
42 |
43 | import { MinusIcon } from "@chakra-ui/icons";
44 |
45 | import InlineSpinner from "../spinners/Inline";
46 | import FormErrors from "../forms/FormErrors";
47 |
48 | import config from "./config";
49 |
50 | const WithdrawModal = ({
51 | farmId,
52 | userTokenBalance,
53 | depositAmount,
54 | usersTotalDepositied,
55 | isWithdrawing,
56 | setIsWithdrawing,
57 | }) => {
58 | const wallet = useWallet();
59 | const { dmtStaking } = useContracts();
60 |
61 | const [tokenInputValue, setTokenInputValue] = useState("");
62 | const prevIsWithdrawing = usePrevious(!isWithdrawing ? false : true);
63 |
64 | const { isOpen, onOpen, onClose } = useDisclosure();
65 |
66 | const closeBtnStyles = useStyleConfig("Button", { variant: "icon-trans" });
67 | const withdrawBtnStyles = useStyleConfig("Button", { variant: "icon-round" });
68 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
69 | const cancelBtnStyles = useStyleConfig("Button", { variant: "ghost-matched" });
70 |
71 | const isModalCentered = useBreakpointValue({ base: false, md: true });
72 |
73 | const [formErrors, setFormErrors] = useState(null);
74 |
75 | /**
76 | * Close modal once withdrawal transaction completes (previous deposit amount !== latest deposit amount).
77 | */
78 | useEffect(() => {
79 | if (prevIsWithdrawing && !isWithdrawing) onClose();
80 | }, [isWithdrawing]);
81 |
82 | const handleTokenInputChange = event => {
83 | const value = _get(event, "target.value");
84 |
85 | checkTokenInputValue(value);
86 |
87 | setTokenInputValue(value);
88 | };
89 |
90 | const handleMaxValueClick = () => {
91 | checkTokenInputValue(depositAmount);
92 |
93 | setTokenInputValue(depositAmount);
94 | };
95 |
96 | const handleWithdrawClick = () => {
97 | const formattedValue = _trim(tokenInputValue.toString());
98 |
99 | if (
100 | !checkTokenInputValue(tokenInputValue) ||
101 | !formattedValue ||
102 | !isWalletConnected(wallet) ||
103 | !wallet.ethereum
104 | ) {
105 | return;
106 | }
107 |
108 | dmtStaking.withdraw(ethersUtils.parseEther(formattedValue))
109 | .then(_ => {
110 | setTokenInputValue("");
111 |
112 | setIsWithdrawing(true);
113 | })
114 | .catch(_ => {});
115 | };
116 |
117 | const checkTokenInputValue = value => {
118 | if (value === "") {
119 | setFormErrors(null);
120 |
121 | return false;
122 | }
123 |
124 | const errors = [];
125 |
126 | if (!isValidNumber(value, 0.00001, depositAmount)) errors.push("Enter a valid amount.");
127 |
128 | if (_size(errors)) {
129 | setFormErrors(errors);
130 |
131 | return false;
132 | }
133 |
134 | setFormErrors(null);
135 |
136 | return true;
137 | };
138 |
139 | const {
140 | openTooltipCopy,
141 | titleCopy,
142 | tokenIcon: TokenIcon,
143 | userTotalDepositedCopy,
144 | usersTotalDepositedCopy,
145 | userBalanceCopy,
146 | spinnerMessage,
147 | } = config[farmId].withdrawModal;
148 |
149 | return (
150 | <>
151 |
161 | }
167 | />
168 |
169 |
178 |
179 |
180 |
188 | {titleCopy}
189 |
190 |
191 |
192 |
193 |
194 |
195 |
200 |
201 |
202 |
203 | {userTotalDepositedCopy}
204 | {formatNumber(depositAmount)}
205 |
206 |
207 |
208 |
209 | {usersTotalDepositedCopy}
210 | {formatNumber(usersTotalDepositied)}
211 |
212 |
213 |
214 |
215 | {userBalanceCopy} {formatNumber(userTokenBalance)}
216 |
217 |
218 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 | >
261 | );
262 | };
263 |
264 | WithdrawModal.propTypes = {
265 | farmId: PropTypes.string.isRequired,
266 | userTokenBalance: PropTypes.number,
267 | depositAmount: PropTypes.number,
268 | usersTotalDepositied: PropTypes.number,
269 | isWithdrawing: PropTypes.bool.isRequired,
270 | setIsWithdrawing: PropTypes.func.isRequired,
271 | };
272 |
273 | export default WithdrawModal;
274 |
--------------------------------------------------------------------------------
/lib/erc20.js:
--------------------------------------------------------------------------------
1 | import { Contract, utils } from "ethers";
2 |
3 | const abi = [
4 | {
5 | constant: true,
6 | inputs: [],
7 | name: "name",
8 | outputs: [{ name: "", type: "string" }],
9 | payable: false,
10 | stateMutability: "view",
11 | type: "function",
12 | },
13 | {
14 | constant: false,
15 | inputs: [
16 | { name: "spender", type: "address" },
17 | { name: "value", type: "uint256" },
18 | ],
19 | name: "approve",
20 | outputs: [{ name: "", type: "bool" }],
21 | payable: false,
22 | stateMutability: "nonpayable",
23 | type: "function",
24 | },
25 | {
26 | constant: false,
27 | inputs: [
28 | { name: "name", type: "string" },
29 | { name: "symbol", type: "string" },
30 | { name: "decimals", type: "uint8" },
31 | ],
32 | name: "initialize",
33 | outputs: [],
34 | payable: false,
35 | stateMutability: "nonpayable",
36 | type: "function",
37 | },
38 | {
39 | constant: true,
40 | inputs: [],
41 | name: "totalSupply",
42 | outputs: [{ name: "", type: "uint256" }],
43 | payable: false,
44 | stateMutability: "view",
45 | type: "function",
46 | },
47 | {
48 | constant: false,
49 | inputs: [{ name: "paused", type: "bool" }],
50 | name: "setRebasePaused",
51 | outputs: [],
52 | payable: false,
53 | stateMutability: "nonpayable",
54 | type: "function",
55 | },
56 | {
57 | constant: false,
58 | inputs: [
59 | { name: "from", type: "address" },
60 | { name: "to", type: "address" },
61 | { name: "value", type: "uint256" },
62 | ],
63 | name: "transferFrom",
64 | outputs: [{ name: "", type: "bool" }],
65 | payable: false,
66 | stateMutability: "nonpayable",
67 | type: "function",
68 | },
69 | {
70 | constant: false,
71 | inputs: [{ name: "paused", type: "bool" }],
72 | name: "setTokenPaused",
73 | outputs: [],
74 | payable: false,
75 | stateMutability: "nonpayable",
76 | type: "function",
77 | },
78 | {
79 | constant: true,
80 | inputs: [],
81 | name: "decimals",
82 | outputs: [{ name: "", type: "uint8" }],
83 | payable: false,
84 | stateMutability: "view",
85 | type: "function",
86 | },
87 | {
88 | constant: false,
89 | inputs: [
90 | { name: "spender", type: "address" },
91 | { name: "addedValue", type: "uint256" },
92 | ],
93 | name: "increaseAllowance",
94 | outputs: [{ name: "", type: "bool" }],
95 | payable: false,
96 | stateMutability: "nonpayable",
97 | type: "function",
98 | },
99 | {
100 | constant: true,
101 | inputs: [],
102 | name: "rebasePaused",
103 | outputs: [{ name: "", type: "bool" }],
104 | payable: false,
105 | stateMutability: "view",
106 | type: "function",
107 | },
108 | {
109 | constant: true,
110 | inputs: [{ name: "who", type: "address" }],
111 | name: "balanceOf",
112 | outputs: [{ name: "", type: "uint256" }],
113 | payable: false,
114 | stateMutability: "view",
115 | type: "function",
116 | },
117 | {
118 | constant: false,
119 | inputs: [],
120 | name: "renounceOwnership",
121 | outputs: [],
122 | payable: false,
123 | stateMutability: "nonpayable",
124 | type: "function",
125 | },
126 | {
127 | constant: false,
128 | inputs: [
129 | { name: "epoch", type: "uint256" },
130 | { name: "supplyDelta", type: "int256" },
131 | ],
132 | name: "rebase",
133 | outputs: [{ name: "", type: "uint256" }],
134 | payable: false,
135 | stateMutability: "nonpayable",
136 | type: "function",
137 | },
138 | {
139 | constant: true,
140 | inputs: [],
141 | name: "tokenPaused",
142 | outputs: [{ name: "", type: "bool" }],
143 | payable: false,
144 | stateMutability: "view",
145 | type: "function",
146 | },
147 | {
148 | constant: false,
149 | inputs: [{ name: "monetaryPolicy_", type: "address" }],
150 | name: "setMonetaryPolicy",
151 | outputs: [],
152 | payable: false,
153 | stateMutability: "nonpayable",
154 | type: "function",
155 | },
156 | {
157 | constant: true,
158 | inputs: [],
159 | name: "owner",
160 | outputs: [{ name: "", type: "address" }],
161 | payable: false,
162 | stateMutability: "view",
163 | type: "function",
164 | },
165 | {
166 | constant: true,
167 | inputs: [],
168 | name: "monetaryPolicy",
169 | outputs: [{ name: "", type: "address" }],
170 | payable: false,
171 | stateMutability: "view",
172 | type: "function",
173 | },
174 | {
175 | constant: true,
176 | inputs: [],
177 | name: "isOwner",
178 | outputs: [{ name: "", type: "bool" }],
179 | payable: false,
180 | stateMutability: "view",
181 | type: "function",
182 | },
183 | {
184 | constant: true,
185 | inputs: [],
186 | name: "symbol",
187 | outputs: [{ name: "", type: "string" }],
188 | payable: false,
189 | stateMutability: "view",
190 | type: "function",
191 | },
192 | {
193 | constant: false,
194 | inputs: [
195 | { name: "spender", type: "address" },
196 | { name: "subtractedValue", type: "uint256" },
197 | ],
198 | name: "decreaseAllowance",
199 | outputs: [{ name: "", type: "bool" }],
200 | payable: false,
201 | stateMutability: "nonpayable",
202 | type: "function",
203 | },
204 | {
205 | constant: false,
206 | inputs: [
207 | { name: "to", type: "address" },
208 | { name: "value", type: "uint256" },
209 | ],
210 | name: "transfer",
211 | outputs: [{ name: "", type: "bool" }],
212 | payable: false,
213 | stateMutability: "nonpayable",
214 | type: "function",
215 | },
216 | {
217 | constant: false,
218 | inputs: [{ name: "owner_", type: "address" }],
219 | name: "initialize",
220 | outputs: [],
221 | payable: false,
222 | stateMutability: "nonpayable",
223 | type: "function",
224 | },
225 | {
226 | constant: true,
227 | inputs: [
228 | { name: "owner_", type: "address" },
229 | { name: "spender", type: "address" },
230 | ],
231 | name: "allowance",
232 | outputs: [{ name: "", type: "uint256" }],
233 | payable: false,
234 | stateMutability: "view",
235 | type: "function",
236 | },
237 | {
238 | constant: false,
239 | inputs: [{ name: "newOwner", type: "address" }],
240 | name: "transferOwnership",
241 | outputs: [],
242 | payable: false,
243 | stateMutability: "nonpayable",
244 | type: "function",
245 | },
246 | {
247 | anonymous: false,
248 | inputs: [
249 | { indexed: true, name: "epoch", type: "uint256" },
250 | { indexed: false, name: "totalSupply", type: "uint256" },
251 | ],
252 | name: "LogRebase",
253 | type: "event",
254 | },
255 | {
256 | anonymous: false,
257 | inputs: [{ indexed: false, name: "paused", type: "bool" }],
258 | name: "LogRebasePaused",
259 | type: "event",
260 | },
261 | {
262 | anonymous: false,
263 | inputs: [{ indexed: false, name: "paused", type: "bool" }],
264 | name: "LogTokenPaused",
265 | type: "event",
266 | },
267 | {
268 | anonymous: false,
269 | inputs: [{ indexed: false, name: "monetaryPolicy", type: "address" }],
270 | name: "LogMonetaryPolicyUpdated",
271 | type: "event",
272 | },
273 | {
274 | anonymous: false,
275 | inputs: [{ indexed: true, name: "previousOwner", type: "address" }],
276 | name: "OwnershipRenounced",
277 | type: "event",
278 | },
279 | {
280 | anonymous: false,
281 | inputs: [
282 | { indexed: true, name: "previousOwner", type: "address" },
283 | { indexed: true, name: "newOwner", type: "address" },
284 | ],
285 | name: "OwnershipTransferred",
286 | type: "event",
287 | },
288 | {
289 | anonymous: false,
290 | inputs: [
291 | { indexed: true, name: "from", type: "address" },
292 | { indexed: true, name: "to", type: "address" },
293 | { indexed: false, name: "value", type: "uint256" },
294 | ],
295 | name: "Transfer",
296 | type: "event",
297 | },
298 | {
299 | anonymous: false,
300 | inputs: [
301 | { indexed: true, name: "owner", type: "address" },
302 | { indexed: true, name: "spender", type: "address" },
303 | { indexed: false, name: "value", type: "uint256" },
304 | ],
305 | name: "Approval",
306 | type: "event",
307 | },
308 | ];
309 |
310 | export const create = (address, provider) => {
311 | const contract = new Contract(address, abi, provider);
312 |
313 | // READ
314 | const balanceOf = (address) =>
315 | contract.balanceOf(address).then(utils.formatEther);
316 |
317 | const allowance = (owner, spender) => contract.allowance(owner, spender); // owner (current user address), spender (contract address)
318 |
319 | // WRITE
320 | const approve = (spender, value) => contract.approve(spender, value); // spender (contract address), value (ethers.utils.parseEther(99999))
321 |
322 | const decreaseAllowance = (spender, subtractedValue) =>
323 | contract.decreaseAllowance(spender, subtractedValue); // spender (contract address), subtractedValue (ethers.utils.parseEther(12345))
324 |
325 | return {
326 | address,
327 | balanceOf,
328 | allowance,
329 | approve,
330 | decreaseAllowance,
331 | };
332 | };
333 |
--------------------------------------------------------------------------------
/pages/farms/[farmId].js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { useRouter } from "next/router";
3 | import { useWallet } from "use-wallet";
4 | import { utils as ethersUtils } from "ethers";
5 | import useInterval from "../../hooks/useInterval";
6 |
7 | import { useContracts } from "../../hooks/useContracts";
8 | import { isWalletConnected, getWalletAddress } from "../../lib/wallet";
9 |
10 | import { isValidNumber } from "../../lib/numeric";
11 |
12 | import usePageTitle from "../../hooks/usePageTitle";
13 |
14 | import { Flex, Box, Heading, Button, useStyleConfig } from "@chakra-ui/core";
15 |
16 | import _get from "lodash/get";
17 | import _isUndefined from "lodash/isUndefined";
18 |
19 | import FarmDepositCard from "../../components/farms/DepositCard";
20 | import FarmEarnCard from "../../components/farms/EarnCard";
21 |
22 | import InlineSpinner from "../../components/spinners/Inline";
23 |
24 | import config from "../../components/farms/config";
25 |
26 | /**
27 | * Match URL slug to farm config key.
28 | * If slug doesn't match, default to yTSLA.
29 | */
30 | const getFarmId = (slug) => {
31 | const idMatrix = { ytsla: "yTslaForDMT" };
32 | const matchedId = idMatrix[slug];
33 |
34 | return matchedId || idMatrix.ytsla;
35 | };
36 |
37 | const approvalAmount = 99999;
38 |
39 | const Farm = () => {
40 | const wallet = useWallet();
41 |
42 | const { ytslaToken, dmtStaking } = useContracts();
43 |
44 | const router = useRouter();
45 |
46 | const primaryBtnStyles = useStyleConfig("Button", { variant: "primary" });
47 |
48 | /**
49 | * Used when navigating from the farms landing view to deactivate the initial spinner.
50 | */
51 | const [isCheckingApproved, setIsCheckingApproved] = useState(true);
52 |
53 | /**
54 | * Polling sets this to true on success.
55 | */
56 | const [isApproved, setIsApproved] = useState(false);
57 |
58 | /**
59 | * If the user fails the initial approval (initialed when navigating from the
60 | * farms landing view) then use this to control the approving spinner state.
61 | */
62 | const [isApproving, setIsApproving] = useState(false);
63 |
64 | /**
65 | * Total amount of yTSLA staked by the user.
66 | */
67 | const [depositAmount, setDepositAmount] = useState(null);
68 |
69 | /**
70 | * Total amount of DMT earned by the user.
71 | */
72 | const [earnedAmount, setEarnedAmount] = useState(null);
73 |
74 | /**
75 | * Used to hide deposit, withdraw, and harvesting spinners.
76 | */
77 | const [prevDepositAmount, setPrevDepositAmount] = useState(null);
78 | const [isDepositing, setIsDepositing] = useState(false);
79 | const [isWithdrawing, setIsWithdrawing] = useState(false);
80 | const [isHarvesting, setIsHarvesting] = useState(false);
81 | const [prevEarnedAmount, setPrevEarnedAmount] = useState(null);
82 |
83 | useInterval(() => {
84 | async function updateLiveInfo() {
85 | if (!checkWallet()) return;
86 |
87 | /**
88 | * Check account approval status and fetch staking data.
89 | */
90 | const liveAllowance = await ytslaToken.allowance(
91 | getWalletAddress(wallet),
92 | dmtStaking.address
93 | );
94 | const isLiveApproved = liveAllowance.gt(ethersUtils.parseEther("1"));
95 | let liveDepositAmount = await dmtStaking.balanceOf(
96 | getWalletAddress(wallet)
97 | );
98 | let liveEarnedAmount = await dmtStaking.earned(getWalletAddress(wallet));
99 |
100 | /**
101 | * Attempt to convert live values to JS safe numeric.
102 | */
103 | liveDepositAmount = parseFloat(
104 | ethersUtils.formatEther(liveDepositAmount)
105 | );
106 | liveEarnedAmount = parseFloat(ethersUtils.formatEther(liveEarnedAmount));
107 |
108 | if (!_isUndefined(isCheckingApproved)) {
109 | if (isCheckingApproved) setIsCheckingApproved(false);
110 | if (isLiveApproved !== isApproved) setIsApproved(isLiveApproved);
111 | if (isLiveApproved) setIsApproving(false);
112 | if (liveDepositAmount !== depositAmount)
113 | setDepositAmount(
114 | isValidNumber(liveDepositAmount) ? liveDepositAmount : 0
115 | );
116 | if (liveEarnedAmount !== earnedAmount)
117 | setEarnedAmount(
118 | isValidNumber(liveEarnedAmount) ? liveEarnedAmount : 0
119 | );
120 |
121 | /**
122 | * Deposit and withdraw spinners.
123 | */
124 | if (
125 | !isDepositing &&
126 | !isWithdrawing &&
127 | liveDepositAmount !== prevDepositAmount
128 | ) {
129 | /**
130 | * Safe to update as user does not have a deposit/withdrawal transaction in-flight.
131 | */
132 | setPrevDepositAmount(
133 | isValidNumber(liveDepositAmount) ? liveDepositAmount : 0
134 | );
135 | } else if (liveDepositAmount !== prevDepositAmount) {
136 | /**
137 | * User has submitted has a deposit transaction (either deposit or withdraw).
138 | * Disable the spinner if the latest amount differs from the previous amount.
139 | */
140 | if (isDepositing) setIsDepositing(false);
141 | if (isWithdrawing) setIsWithdrawing(false);
142 | }
143 |
144 | /**
145 | * Harvesting spinners.
146 | */
147 | if (!isHarvesting && liveEarnedAmount !== prevEarnedAmount) {
148 | /**
149 | * Safe to update as user does not have a harvest transaction in-flight.
150 | */
151 | setPrevEarnedAmount(
152 | isValidNumber(liveEarnedAmount) ? liveEarnedAmount : 0
153 | );
154 | } else if (liveEarnedAmount !== prevEarnedAmount) {
155 | /**
156 | * User has submitted has a harvest transaction (either harvest or harvest & withdraw).
157 | * Disable the spinner if the latest amount differs from the previous amount.
158 | */
159 | if (isHarvesting) setIsHarvesting(false);
160 | }
161 | }
162 | }
163 |
164 | updateLiveInfo().catch(console.log);
165 | }, 2000);
166 |
167 | const farmId = getFarmId(_get(router, "query.farmId"));
168 |
169 | const handleApproveClick = () => {
170 | ytslaToken
171 | .approve(
172 | dmtStaking.address,
173 | ethersUtils.parseEther(approvalAmount.toString())
174 | )
175 | .then((_) => setIsApproving(true))
176 | .catch((_) => setIsApproving(false));
177 | };
178 |
179 | const handleHarvestWithdrawClick = () => {
180 | if (!depositAmount || !isWalletConnected(wallet) || !wallet.ethereum) {
181 | return;
182 | }
183 |
184 | dmtStaking
185 | .withdraw(ethersUtils.parseEther(depositAmount.toString()))
186 | .then((_) => setIsHarvesting(true))
187 | .catch((_) => {});
188 | };
189 |
190 | const checkWallet = () => {
191 | if (!isWalletConnected(wallet) || !wallet.ethereum) {
192 | router.push("/farms");
193 |
194 | return false;
195 | }
196 |
197 | return true;
198 | };
199 |
200 | const { titleCopy, withdrawAllBtnCopy } = config[farmId].farm;
201 |
202 | usePageTitle(titleCopy);
203 |
204 | return (
205 |
214 |
218 |
219 |
228 | {titleCopy}
229 |
230 |
236 |
247 |
255 |
256 | {(isApproved && !!depositAmount) && (
257 |
258 |
263 |
271 |
272 |
273 | )}
274 |
275 |
276 |
277 | );
278 | };
279 |
280 | export default Farm;
281 |
--------------------------------------------------------------------------------
/pages/gallery.js:
--------------------------------------------------------------------------------
1 | import { useState, useMemo } from "react";
2 | import { useWallet } from "use-wallet";
3 | import { utils as ethersUtils } from "ethers";
4 | import {
5 | Flex,
6 | Modal,
7 | ModalOverlay,
8 | ModalContent,
9 | useDisclosure,
10 | useBreakpointValue,
11 | } from "@chakra-ui/core";
12 | import { formatNumber } from "../lib/numeric";
13 | import useInterval from "../hooks/useInterval";
14 | import usePageTitle from "../hooks/usePageTitle";
15 | import {
16 | Level1,
17 | Level2,
18 | Level3,
19 | Level4,
20 | Level5,
21 | Level6,
22 | Level7,
23 | } from "../components/story";
24 | import { isWalletConnected, getWalletAddress } from "../lib/wallet";
25 | import { useContracts } from "../hooks/useContracts";
26 | import ManageStakeModal from "../components/gallery/ManageStakeModal";
27 | import GalleryCard from "../components/gallery/GalleryCard";
28 | import InputPassword from "../components/gallery/InputPassword";
29 |
30 | const approvalAmount = 22222;
31 |
32 | const CARD_BACK_URL =
33 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AACIl90UuDCLeAG6ct5clfLxa/BLANK.mp4?raw=1";
34 |
35 | const nftData = [
36 | {
37 | id: "1",
38 | name: "Pineapple Gate",
39 | image:
40 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AABXvXyTZgB9jASiNVHH46Zoa/DMT_1.mp4?raw=1",
41 | },
42 | {
43 | id: "2",
44 | name: "Cosmic Fuel",
45 | image:
46 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAC2YeY40K1U8PkZXuaK-9Bua/DMT_2.mp4?raw=1",
47 | },
48 | {
49 | id: "3",
50 | name: "Rug in Prod",
51 | image:
52 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAD4X1giMZlsI_MUBP_owSU6a/DMT_3.mp4?raw=1",
53 | },
54 | {
55 | id: "4",
56 | name: "Proof of Ponzi",
57 | image:
58 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AACF30g4PvM3ewjWu1Q32n6ca/DMT_4.mp4?raw=1",
59 | },
60 | {
61 | id: "5",
62 | name: "Bloody Sushi",
63 | image:
64 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AADGKGpkGBDK8e1AFCi3bDb4a/DMT_5.mp4?raw=1",
65 | },
66 | {
67 | id: "6",
68 | name: "Masochist Munchies",
69 | image:
70 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AABWLf9qAG0yuipHqy4LY-6na/DMT_6.mp4?raw=1",
71 | },
72 | {
73 | id: "7",
74 | name: "Daddy's Home",
75 | image:
76 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AAAv6JVLHHxdeYAyM51Ryub_a/DMT_7.mp4?raw=1",
77 | },
78 | {
79 | id: "8",
80 | name: "NFT 8",
81 | image:
82 | "https://www.dropbox.com/sh/a43mnv6kg9t0yi2/AADeMva6tjAE1i6gv3rkMFOfa/DMT_8.mp4?raw=1",
83 | },
84 | ];
85 |
86 | const Gallery = () => {
87 | usePageTitle("Gallery");
88 |
89 | const wallet = useWallet();
90 | const { nftStaking, dmtLpToken, dmtLtd } = useContracts();
91 | const { isOpen, onOpen, onClose } = useDisclosure();
92 | const isModalCentered = useBreakpointValue({ base: false, md: true });
93 |
94 | const [current, setCurrent] = useState(0);
95 | const [showPasswordInput, setShowInputPassword] = useState(false);
96 | const [selectedCard, setSelectedCard] = useState(-1);
97 |
98 | const [earnedAmount, setEarnedAmount] = useState(0);
99 | const [depositStakedAmount, setDepositStakedAmount] = useState(0);
100 | const [userTokenBalance, setUserTokenBalance] = useState(0);
101 |
102 | const [isApproved, setIsApproved] = useState(false);
103 | const [isApproving, setIsApproving] = useState(false);
104 | const [arrMaxSupply, setArrMaxSupply] = useState(new Array(8).fill(0));
105 | const [arrAvailableSupply, setArrAvailableSupply] = useState(
106 | new Array(8).fill(0)
107 | );
108 | const [arrCards, setArrCards] = useState(new Array(8).fill(0));
109 | const [ownedCards, setOwnedCards] = useState(new Array(8).fill(0));
110 |
111 | const currentCard = useMemo(() => {
112 | let i = ownedCards.length - 1;
113 | while (i >= 0 && ownedCards[i] === 0) {
114 | i--;
115 | }
116 | return i + 1;
117 | }, [ownedCards]);
118 |
119 | const [isDepositing, setIsDepositing] = useState(false);
120 | const [isWithdrawing, setIsWithdrawing] = useState(false);
121 |
122 | const handleUnlock = async (card) => {
123 | if (card === "4" || card === "7") {
124 | setSelectedCard(card);
125 | setShowInputPassword(true);
126 | } else {
127 | await nftStaking.redeem(card).catch(() => {
128 | window.alert("Do you hold the right key?");
129 | });
130 | setSelectedCard(-1);
131 | }
132 | };
133 |
134 | const checkWallet = () => {
135 | if (!isWalletConnected(wallet) || !wallet.ethereum) {
136 | return false;
137 | }
138 |
139 | return true;
140 | };
141 |
142 | useInterval(() => {
143 | async function checkLiveInfo() {
144 | const array2 = [];
145 | for (let i = 1; i <= 8; i++) {
146 | array2.push(dmtLtd.totalSupply(i));
147 | }
148 | await Promise.all(array2).then((result) => setArrAvailableSupply(result));
149 |
150 | if (arrMaxSupply[0] === 0) {
151 | const array1 = [];
152 | for (let i = 1; i <= 8; i++) {
153 | array1.push(dmtLtd.tokenMaxSupply(i));
154 | }
155 | await Promise.all(array1).then((result) => setArrMaxSupply(result));
156 | }
157 |
158 | if (arrCards[0] === 0) {
159 | const array3 = [];
160 | for (let i = 1; i <= 8; i++) {
161 | array3.push(nftStaking.cards(i));
162 | }
163 | await Promise.all(array3).then((result) => setArrCards(result));
164 | }
165 |
166 | if (!checkWallet()) return;
167 |
168 | const array4 = [];
169 | for (let i = 1; i <= 8; i++) {
170 | array4.push(dmtLtd.balanceOf(wallet.account, i));
171 | }
172 | await Promise.all(array4).then((result) => setOwnedCards(result));
173 |
174 | const liveAllowance = await dmtLpToken.allowance(
175 | wallet.account,
176 | nftStaking.address
177 | );
178 |
179 | const isLiveApproved = liveAllowance.gt(
180 | ethersUtils.parseEther((approvalAmount / 2).toString())
181 | );
182 |
183 | if (isLiveApproved !== isApproved) setIsApproved(isLiveApproved);
184 | if (isLiveApproved) setIsApproving(false);
185 |
186 | const liveDepositBalance = await nftStaking.balanceOf(wallet.account);
187 |
188 | if (liveDepositBalance !== depositStakedAmount) {
189 | setDepositStakedAmount(liveDepositBalance);
190 | if (isDepositing) setIsDepositing(false);
191 | if (isWithdrawing) setIsWithdrawing(false);
192 | }
193 |
194 | const liveTokenBalance = await dmtLpToken.balanceOf(wallet.account);
195 |
196 | if (liveTokenBalance !== userTokenBalance)
197 | setUserTokenBalance(liveTokenBalance);
198 |
199 | const liveEarnedBalance = await nftStaking.earned(wallet.account);
200 |
201 | if (liveEarnedBalance !== earnedAmount)
202 | setEarnedAmount(liveEarnedBalance);
203 | }
204 |
205 | checkLiveInfo().catch((e) => console.log("err"));
206 | }, 2000);
207 |
208 | const handleApproveClick = () => {
209 | setIsApproving(true);
210 | dmtLpToken
211 | .approve(
212 | nftStaking.address,
213 | ethersUtils.parseEther(approvalAmount.toString())
214 | )
215 | .catch((_) => setIsApproving(false));
216 | };
217 |
218 | return (
219 |
229 | {checkWallet() && (
230 |
239 |
251 | {formatNumber(depositStakedAmount, 6)} DMT LP Staked
252 |
253 |
266 | {formatNumber(earnedAmount, 3)} NaOH Earned
267 |
268 |
280 |
281 | )}
282 | {showPasswordInput && (
283 | {
286 | await nftStaking.redeem(selectedCard).catch(console.error);
287 | setSelectedCard(-1);
288 | setShowInputPassword(false);
289 | }}
290 | onClose={() => {
291 | setSelectedCard(-1);
292 | setShowInputPassword(false);
293 | }}
294 | />
295 | )}
296 |
304 | {nftData.map(({ id, name, image }, index) =>
305 | index <= 5 ? (
306 |
321 | ) : null
322 | )}
323 |
324 |
333 |
347 |
348 |
357 |
358 |
364 | {current === 1 && }
365 | {current === 2 && }
366 | {current === 3 && }
367 | {current === 4 && }
368 | {current === 5 && }
369 | {current === 6 && }
370 | {current === 7 && }
371 |
372 |
373 |
374 |
375 | );
376 | };
377 |
378 | export default Gallery;
379 |
--------------------------------------------------------------------------------