Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STIP rewards page #716

Merged
merged 5 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/front-end/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Route, Routes, Navigate } from "react-router-dom";
import { Navigate, Route, Routes } from "react-router-dom";
import { ToastContainer } from "react-toastify";

import ApolloProvider from "./clients/Apollo/Apollo";
Expand All @@ -8,14 +8,15 @@ import { Header } from "./components/Header";
import { Init } from "./components/Init";
import { MobileWarning } from "./components/MobileWarning";
import { AppPaths } from "./config/appPaths";
import { useScrollToTop } from "./hooks/useScrollToTop";
import { Dashboard } from "./pages/Dashboard";
import { OTC } from "./pages/OTC";
import { OptionsTrading } from "./pages/OptionsTrading";
import { PrivacyPolicy } from "./pages/PrivacyPolicy";
import { Rewards } from "./pages/Rewards";
import { TermsOfService } from "./pages/TermsOfService";
import { Vault } from "./pages/Vault";
import { GlobalContextProvider } from "./state/GlobalContext";
import { useScrollToTop } from "./hooks/useScrollToTop";

import "react-toastify/dist/ReactToastify.css";
import "./App.css";
Expand All @@ -41,6 +42,7 @@ function App() {
path={AppPaths.PRIVACY_POLICY}
element={<PrivacyPolicy />}
/>
<Route path={AppPaths.REWARDS} element={<Rewards />} />
<Route
path={AppPaths.TERMS_OF_SERVICE}
element={<TermsOfService />}
Expand Down
39 changes: 39 additions & 0 deletions packages/front-end/src/Icons/ARB.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { SVGProps } from "react";

export const ARB = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 2500 2500"
strokeWidth={1.5}
stroke="currentColor"
className="w-6 h-6"
{...props}
>
<path
fill="#213147"
d="M226,760v980c0,63,33,120,88,152l849,490c54,31,121,31,175,0l849-490c54-31,88-89,88-152V760 c0-63-33-120-88-152l-849-490c-54-31-121-31-175,0L314,608c-54,31-87,89-87,152H226z"
/>
<path
fill="#12AAFF"
d="M1435,1440l-121,332c-3,9-3,19,0,29l208,571l241-139l-289-793C1467,1422,1442,1422,1435,1440z"
/>
<path
fill="#12AAFF"
d="M1678,882c-7-18-32-18-39,0l-121,332c-3,9-3,19,0,29l341,935l241-139L1678,883V882z"
/>
<path
fill="#9DCCED"
d="M1250,155c6,0,12,2,17,5l918,530c11,6,17,18,17,30v1060c0,12-7,24-17,30l-918,530c-5,3-11,5-17,5 s-12-2-17-5l-918-530c-11-6-17-18-17-30V719c0-12,7-24,17-30l918-530c5-3,11-5,17-5l0,0V155z M1250,0c-33,0-65,8-95,25L237,555 c-59,34-95,96-95,164v1060c0,68,36,130,95,164l918,530c29,17,62,25,95,25s65-8,95-25l918-530c59-34,95-96,95-164V719 c0-68-36-130-95-164L1344,25c-29-17-62-25-95-25l0,0H1250z"
/>
<polygon fill="#213147" points="642,2179 727,1947 897,2088 738,2234 " />
<path
fill="#FFFFFF"
d="M1172,644H939c-17,0-33,11-39,27L401,2039l241,139l550-1507c5-14-5-28-19-28L1172,644z"
/>
<path
fill="#FFFFFF"
d="M1580,644h-233c-17,0-33,11-39,27L738,2233l241,139l620-1701c5-14-5-28-19-28V644z"
/>
</svg>
);
2 changes: 2 additions & 0 deletions packages/front-end/src/Icons/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ARB } from "./ARB";
import { Change } from "./Change";
import { ChevronUpDown } from "./ChevronUpDown";
import { Close } from "./Close";
Expand All @@ -23,6 +24,7 @@ import { UpChevron } from "./UpChevron";
import { WETH } from "./WETH";

export {
ARB,
Change,
ChevronUpDown,
Close,
Expand Down
1 change: 1 addition & 0 deletions packages/front-end/src/clients/Apollo/Queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export enum QueriesEnum {
DASHBOARD_USER_POSITIONS = "DASHBOARD_USER_POSITIONS",
INITIAL_DATA = "INITIAL_DATA",
ORACLE_ASSETS = "ORACLE_ASSETS",
REWARDS = "REWARDS",
TRANSACTIONS = "TRANSACTIONS",
USER_EPOCH_PNL = "USER_EPOCH_PNL",
USER_VAULT = "USER_VAULT",
Expand Down
1 change: 1 addition & 0 deletions packages/front-end/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const links = [
{ id: "header-options", path: AppPaths.TRADE, label: "Trade Options" },
{ id: "header-vault", path: AppPaths.VAULT, label: "Vault" },
{ id: "header-dashboard", path: AppPaths.DASHBOARD, label: "Dashboard" },
{ id: "header-rewards", path: AppPaths.REWARDS, label: "Rewards" },
];

export const Header = () => {
Expand Down
83 changes: 83 additions & 0 deletions packages/front-end/src/components/Rewards/components/Active.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import dayjs from "dayjs";
import { Link as RouterLink } from "react-router-dom";

import { Link } from "src/Icons";

const rewardPrograms = [
{
dates: {
start: dayjs.unix(1698998400),
end: dayjs.unix(1707465600),
},
info: (
<>
{`The Arbitrum short term incentive program will provide `}
<b>{`35.6k ARB`}</b>
{` per week, split evenly between liquidity providers and traders. Anyone with a deposit in the DHV when the weekly epoch is executed will be eligible for rewards. Equally, every contract traded during the epoch will be eligible to earn a share of the weekly rewards based on different trading params. To find out more about eligibility and distribution, deposit into the vault, or make a trade, please follow the link below.`}
</>
),
links: [
{
external: true,
href: "https://medium.rysk.finance/arbitrum-stip-rewards-for-rysk-6929609e85d7",
label: "Learn more about the Arbitrum STIP rewards.",
MeanBoyCousin marked this conversation as resolved.
Show resolved Hide resolved
},
{
external: false,
href: "/vault",
label: "Deposit now to earn rewards.",
},
{
external: false,
href: "/",
label: "Start trading now.",
MeanBoyCousin marked this conversation as resolved.
Show resolved Hide resolved
},
],
title: "Arbitrum STIP",
},
];

export const Active = () => (
<section>
<h2 className="text-2xl mb-4 pb-4 border-b border-gray-500">{`Active reward programs`}</h2>

{rewardPrograms.map(({ dates, info, title, links }) => (
<div className="mb-4 pb-4 border-b border-gray-500" key={title}>
<h3 className="text-xl mr-4 mb-2 font-bold">
{title}
<span className="text-xs ml-4">
<time dateTime={dates.start.format("YYYY-MM-DD")}>
{dates.start.format("DD MMM YY")}
</time>
{` - `}
<time dateTime={dates.end.format("YYYY-MM-DD")}>
{dates.end.format("DD MMM YY")}
</time>
</span>
</h3>

<p className="mb-2">{info}</p>

{links.map(({ external, href, label }) => {
return external ? (
<a
className="flex text-sm py-3"
href={href}
key={label}
rel="noopener noreferrer"
target="_blank"
>
<Link className="w-4 h-4 mr-2 my-0.5" />
{label}
</a>
) : (
<RouterLink className="flex text-sm py-3" to={href} key={label}>
<Link className="w-4 h-4 mr-2 my-0.5" />
{label}
</RouterLink>
);
})}
</div>
))}
</section>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const Footnotes = () => (
<section>
<small>{`* Calculated as the USD value of the tokens at the time of distribution.`}</small>
</section>
);
15 changes: 15 additions & 0 deletions packages/front-end/src/components/Rewards/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const Header = () => (
<section className="grid grid-cols-2 font-parabole">
<div>
<h1 className="text-4xl mb-4">{`Rysk Rewards`}</h1>
<h2 className="text-xl ml-[3px]">{`Earn rewards for LPing and Trading on Rysk`}</h2>
</div>

<img
alt="Rysk logo"
className="h-24 m-auto"
src={"/logo-animated.gif"}
title="Rysk: Uncorrelated Returns"
/>
</section>
);
30 changes: 30 additions & 0 deletions packages/front-end/src/components/Rewards/components/Info.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { RecipientsProps } from "../types";

import { RyskCountUp } from "src/components/shared/RyskCountUp";
import { ARB } from "src/Icons";

export const Info = ({ recipients, tokens, value }: RecipientsProps) => (
<section className="grid grid-cols-3 bg-[url('./assets/white-ascii-50.png')] bg-fixed mb-16 py-16 border-2 border-black rounded-lg">
<span className="text-center border-r-2 border-black">
<p className="text-2xl mb-2 font-dm-mono">
<RyskCountUp format="Integer" value={recipients.length || 0} />
</p>
<p className="text-xl">{`Reward recipients`}</p>
</span>

<span className="text-center border-r-2 border-black">
<p className="items-center justify-center flex text-2xl mb-2 font-dm-mono">
<ARB className="w-8 h-8 mr-4" />
<RyskCountUp format="Integer" value={tokens} />
</p>
<p className="text-xl">{`Distributed`}</p>
</span>

<span className="text-center">
<p className="text-2xl mb-2 font-dm-mono">
<RyskCountUp prefix="$ " value={value} />
</p>
<p className="text-xl">{`Total value*`}</p>
</span>
</section>
);
58 changes: 58 additions & 0 deletions packages/front-end/src/components/Rewards/components/Table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { TableProps } from "../types";

import { useAccount } from "wagmi";

import { ARB } from "src/Icons";
import { RyskCountUp } from "src/components/shared/RyskCountUp";
import { Convert } from "src/utils/Convert";
import { shorthandContractAddress } from "src/utils/helpers";

export const Table = ({ recipients }: TableProps) => {
const { address } = useAccount();

return (
<section className="bg-[url('./assets/white-ascii-50.png')] bg-fixed">
<table className="block [&>*]:block text-lg border-2 border-black rounded-lg">
<thead className="w-full border-b-2 border-black border-dashed">
<tr className="grid grid-cols-4 text-center [&_th]:border-l-2 first:[&_th]:border-0 [&_th]:border-gray-500 [&_th]:border-dashed [&_th]:py-3 [&_th]:text-lg">
<th scope="col">{`Rank`}</th>
<th scope="col">{`Address`}</th>
<th scope="col">{`Received`}</th>
<th scope="col">{`Total value*`}</th>
</tr>
</thead>

<tbody>
{recipients.map(({ id, totalTokens, totalValue }, index) => {
const isUser = id === address?.toLowerCase();

return (
<tr
className="relative grid grid-cols-4 items-center text-center font-dm-mono [&_td]:h-11 [&_td]:z-10 [&_td]:flex [&_td]:items-center [&_td]:justify-center [&_td]:border-b [&_td]:border-l-2 first:[&_td]:border-l-0 [&_td]:border-x-gray-500 [&_td]:border-dashed [&_td]:text-base [&_td]:p-0"
key={id}
>
{isUser && (
<td className="absolute w-full bg-cyan/20 animate-pulse" />
)}
<td>{`# ${index + 1}`}</td>
<td>{shorthandContractAddress(id)}</td>
<td>
<ARB className="w-6 h-6 m-auto flex-1 pl-8" />
<p className="m-auto flex-1 pr-8">
<RyskCountUp value={Convert.fromWei(totalTokens).toInt()} />
</p>
</td>
<td>
<RyskCountUp
prefix="$ "
value={Convert.fromStr(totalValue).toInt()}
/>
</td>
</tr>
);
})}
</tbody>
</table>
</section>
);
};
44 changes: 44 additions & 0 deletions packages/front-end/src/components/Rewards/hooks/useAirdropData.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { RewardsQuery, UseAirdropDataValues } from "../types";

import { gql, useQuery } from "@apollo/client";

import { QueriesEnum } from "src/clients/Apollo/Queries";
import { Convert } from "src/utils/Convert";
import { logError } from "src/utils/logError";

/**
* Hook to fetch graph data for airdrops.
* Returns the list of airdrop recipients, the total tokens distributed and their total USD value.
*
* @returns [totalTokens, totalValue] - [total tokens distributed, total USD value of those tokens]
*/
export const useAirdropData = (): UseAirdropDataValues => {
const { data } = useQuery<RewardsQuery>(
gql(`
query ${QueriesEnum.REWARDS} {
airdropRecipients (first: 100, orderBy: totalValue, orderDirection: desc) {
id
totalTokens
totalValue
}
}
`),
{
onError: logError,
}
);

if (!data) return [[], 0, 0];

const [totalTokens, totalValue] = data.airdropRecipients.reduce(
([totalTokens, totalValue], recipient) => {
const tokens = Convert.fromWei(recipient.totalTokens).toInt();
const value = Convert.fromStr(recipient.totalValue).toInt();

return [totalTokens + tokens, totalValue + value];
},
[0, 0]
);

return [data.airdropRecipients, totalTokens, totalValue];
};
20 changes: 20 additions & 0 deletions packages/front-end/src/components/Rewards/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Header } from "./components/Header";
import { Active } from "./components/Active";
import { Footnotes } from "./components/Footnotes";
import { Info } from "./components/Info";
import { Table } from "./components/Table";
import { useAirdropData } from "./hooks/useAirdropData";

export const RewardsContent = () => {
const [recipients, totalTokens, totalValue] = useAirdropData();

return (
<main className="col-start-2 col-end-16 mt-16 text-justify [&_section]:mb-16 last:[&_section]:mb-0">
<Header />
<Active />
<Info recipients={recipients} tokens={totalTokens} value={totalValue} />
<Table recipients={recipients} />
<Footnotes />
</main>
);
};
23 changes: 23 additions & 0 deletions packages/front-end/src/components/Rewards/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export interface RewardsQuery {
airdropRecipients: {
id: HexString;
totalTokens: string;
totalValue: string;
}[];
}

export type UseAirdropDataValues = [
RewardsQuery["airdropRecipients"],
number,
number,
];

export interface RecipientsProps {
recipients: RewardsQuery["airdropRecipients"];
tokens: number;
value: number;
}

export interface TableProps {
recipients: RewardsQuery["airdropRecipients"];
}
1 change: 1 addition & 0 deletions packages/front-end/src/config/appPaths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export enum AppPaths {
HOME = "/",
OTC = "/otc",
PRIVACY_POLICY = "/privacy-policy",
REWARDS = "/rewards",
TERMS_OF_SERVICE = "/terms-of-service",
TRADE = "/options",
VAULT = "/vault",
Expand Down
3 changes: 3 additions & 0 deletions packages/front-end/src/pages/Rewards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { RewardsContent } from "src/components/Rewards";

export const Rewards = () => <RewardsContent />;