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

Update velolrds charts, homepage update. randomise delegate oreder #326

Merged
merged 9 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/nextjs/env.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
/* eslint-disable no-restricted-properties */
import { env as authEnv } from "@realms-world/auth/env";
import { createEnv } from "@t3-oss/env-nextjs";
import { vercel } from "@t3-oss/env-nextjs/presets";
import { z } from "zod";

import { env as authEnv } from "@realms-world/auth/env";

export const env = createEnv({
extends: [authEnv, vercel()],
shared: {
Expand All @@ -21,6 +20,7 @@ export const env = createEnv({
*/
server: {
DATABASE_URL: z.string().url(),
DUNE_API_KEY: z.string().optional(),
},

/**
Expand Down
27 changes: 14 additions & 13 deletions apps/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
"dependencies": {
"@ark-project/react": "1.1.2",
"@avnu/avnu-sdk": "^2.1.1",
"@cartridge/connector": "^0.5.1",
"@cartridge/controller": "^0.5.1",
"@cartridge/connector": "^0.5.5",
"@cartridge/controller": "^0.5.5",
"@duneanalytics/client-sdk": "^0.2.4",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@keystatic/core": "^0.5.36",
Expand All @@ -28,7 +29,7 @@
"@million/lint": "1.0.0-rc.75",
"@mui/material": "^5.15.15",
"@mui/styles": "^5.15.15",
"@next/mdx": "^14.2.15",
"@next/mdx": "^15.1.3",
"@rainbow-me/rainbowkit": "^2",
"@realms-world/api": "workspace:*",
"@realms-world/auth": "workspace:*",
Expand All @@ -39,13 +40,13 @@
"@realms-world/ui": "workspace:*",
"@realms-world/utils": "workspace:*",
"@reservoir0x/reservoir-kit-ui": "^2.5.16",
"@starknet-react/chains": "^3.0.2",
"@starknet-react/core": "^3.0.3",
"@starknet-react/chains": "^3.1.1",
"@starknet-react/core": "^3.6.3",
"@starkware-industries/commons-js-enums": "^1.2.0",
"@starkware-industries/commons-js-utils": "^1.2.2",
"@svgr/webpack": "^8.1.0",
"@t3-oss/env-nextjs": "^0.11.1",
"@tanstack/react-query": "5.59.15",
"@tanstack/react-query": "5.62.15",
"@trpc/client": "11.0.0-rc.477",
"@trpc/react-query": "11.0.0-rc.477",
"@trpc/server": "11.0.0-rc.477",
Expand All @@ -54,29 +55,29 @@
"class-variance-authority": "^0.7.0",
"cmdk": "^1.0.0",
"date-fns": "3.6.0",
"embla-carousel-autoplay": "8.3.0",
"embla-carousel-react": "8.3.0",
"eslint-config-next": "^15.0.0",
"framer-motion": "^11.11.9",
"embla-carousel-autoplay": "8.5.1",
"embla-carousel-react": "8.5.1",
"eslint-config-next": "^15.1.3",
"framer-motion": "^11.15.0",
"frames.js": "^0.15.1",
"gray-matter": "^4.0.3",
"keccak256": "^1.0.6",
"lodash": "4.17.21",
"lucide-react": "^0.441.0",
"merkletreejs": "^0.3.11",
"next": "^15.0.3",
"next": "^15.1.3",
"nuqs": "^1.20.0",
"react": "catalog:react19",
"react-dom": "catalog:react19",
"react-is": "catalog:react19",
"react-virtuoso": "^4.12.0",
"recharts": "^2.13.0",
"recharts": "^2.15.0",
"remark": "^15.0.1",
"remark-html": "^16.0.1",
"server-only": "0.0.1",
"siws": "workspace:*",
"starknet": "6.11.0",
"starknetkit": "^2.3.3",
"starknetkit": "^2.6.1",
"superjson": "2.2.1",
"viem": "^2.21.27",
"wagmi": "^2.12.19",
Expand Down
Binary file added apps/nextjs/public/elizaOS.avif
Binary file not shown.
Binary file added apps/nextjs/public/lords-coin-animation.webm
Binary file not shown.
43 changes: 23 additions & 20 deletions apps/nextjs/src/app/(app)/account/lords/velords/VeLords.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
"use client";

import type { Address } from "@starknet-react/core";
import type { BlockNumber } from "starknet";
import { useMemo, useState } from "react";
import Link from "next/link";
import { VeLords as VeLordsABI } from "@/abi/L2/VeLords";
import { TokenInput } from "@/app/_components/TokenInput";
import { TokenBalance } from "@/app/(app)/bridge/TokenBalance";
import { SUPPORTED_L2_CHAIN_ID } from "@/constants/env";
import type { Address } from "@starknet-react/core";
import { useAccount, useBalance, useReadContract } from "@starknet-react/core";
import { formatEther, parseEther } from "viem";
import { VeLords as VeLordsABI } from "@/abi/L2/VeLords";
import { useVeLords } from "@/hooks/staking/useVeLords";
import { useSimulateTransactions } from "@/hooks/useSimulateTransactions";
import LordsIcon from "@/icons/lords.svg";

import { api } from "@/trpc/react";
import { LORDS, StakingAddresses } from "@realms-world/constants";
import { Badge } from "@realms-world/ui/components/ui/badge";
import { Button } from "@realms-world/ui/components/ui/button";
import {
Card,
Expand All @@ -22,26 +25,26 @@ import {
} from "@realms-world/ui/components/ui/card";
import { Input } from "@realms-world/ui/components/ui/input";
import { Label } from "@realms-world/ui/components/ui/label";
import { Slider } from "@realms-world/ui/components/ui/slider";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@realms-world/ui/components/ui/tabs";
import { Slider } from "@realms-world/ui/components/ui/slider";
import { Badge } from "@realms-world/ui/components/ui/badge";

import { useVeLords } from "@/hooks/staking/useVeLords";
import type { BlockNumber } from "starknet";
import { formatNumber } from "@realms-world/utils";
import { useAccount, useBalance, useReadContract } from "@starknet-react/core";
import {
differenceInSeconds,
formatDistanceToNow,
fromUnixTime,
getUnixTime,
} from "date-fns";
import { motion } from "framer-motion";
import { BlockTag } from "starknet";
import { formatEther, parseEther } from "viem";

import { VeLordsRewardsChart } from "./VeLordsRewardsChart";
import { api } from "@/trpc/react";
import { formatDistanceToNow } from "date-fns";
import { differenceInSeconds, getUnixTime, fromUnixTime } from "date-fns";
import { motion } from "framer-motion";
import { formatNumber } from "@realms-world/utils";
import Link from "next/link";
import { useSimulateTransactions } from "@/hooks/useSimulateTransactions";

const WEEK_IN_SECONDS = 7 * 24 * 60 * 60; // 1 week in seconds
const YEAR_IN_SECONDS = 365 * 24 * 60 * 60; // 1 year in seconds
Expand Down Expand Up @@ -170,7 +173,7 @@ export const VeLords = () => {
}, [ownerLordsLock?.end_time, lockWeeks]);

const timeUntilUnlock = ownerLordsLock?.end_time
? getTimeUntil(Number(ownerLordsLock?.end_time))
? getTimeUntil(Number(ownerLordsLock.end_time))
: undefined;
const weeksToUnlock = toWeeks(timeUntilUnlock);

Expand Down Expand Up @@ -228,7 +231,7 @@ export const VeLords = () => {
<CardHeader>
<CardTitle className="flex items-center">
{ownerLordsLock?.amount &&
formatNumber(Number(formatEther(ownerLordsLock?.amount)))}
formatNumber(Number(formatEther(ownerLordsLock.amount)))}
<LordsIcon className="ml-2 h-7 w-7 fill-current" />
</CardTitle>
</CardHeader>
Expand Down Expand Up @@ -370,7 +373,7 @@ export const VeLords = () => {
</span>
<span className="text-sm opacity-80">
until{" "}
{ownerLordsLock?.end_time &&
{ownerLordsLock.end_time &&
formatLockEndTime(Number(ownerLordsLock.end_time))}
</span>
</Badge>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
"use client";

import { Line, LineChart, CartesianGrid, YAxis, XAxis } from "recharts";
import LordsIcon from "@/icons/lords.svg";

import type { ChartConfig } from "@realms-world/ui/components/ui/chart";
import LordsIcon from "@/icons/lords.svg";
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from "@realms-world/ui/components/ui/chart";
import {
Bar,
BarChart,
CartesianGrid,
Line,
LineChart,
XAxis,
YAxis,
} from "recharts";

const sourceColors = {
"Loot Survivor Fees": "hsl(36 88.9% 85.9%)",
"veLords Early Exit Fees": "hsl(240 88.9% 85.9%)",
Crypts: "hsl(120 88.9% 85.9%)",
// Add more sources and colors as needed
} as const;

const chartConfig = {
total_amount: {
Expand All @@ -28,20 +42,60 @@ export function VeLordsRewardsChart({
data,
totalSupply,
}: {
data?: { total_amount: string; week: string }[];
data?: {
source: string;
amount: string;
transaction_hash: string;
epoch: Date;
epoch_total_amount: string;
sender_epoch_total_amount: string;
}[];
totalSupply?: number;
}) {
const parsedData = totalSupply
? data?.map((item) => ({
week: new Date(item.week).toISOString().split("T")[0], // Convert to YYYY-MM-DD
total_amount: parseFloat(item.total_amount),
apy: ((parseInt(item.total_amount) * 52) / totalSupply) * 100,
}))
: [];
? data
?.reduce(
(acc, item) => {
const week = new Date(item.epoch).toISOString().split("T")[0];
const existingWeek = acc.find((d) => d.week === week);

if (existingWeek) {
// Add to existing week
existingWeek.amounts[item.source] =
(existingWeek.amounts[item.source] || 0) +
parseFloat(item.amount);
existingWeek.total_amount += parseFloat(item.amount);
// Recalculate APY based on total
existingWeek.apy =
((existingWeek.total_amount * 52) / totalSupply) * 100;
} else {
// Create new week entry
acc.push({
week,
amounts: {
[item.source]: parseFloat(item.amount),
},
total_amount: parseFloat(item.amount),
apy: ((parseFloat(item.amount) * 52) / totalSupply) * 100,
});
}
return acc;
},
[] as {
week: string;
amounts: Record<string, number>;
total_amount: number;
apy: number;
}[],
)
.sort((a, b) => a.week.localeCompare(b.week))
: [];
return (
<ChartContainer config={chartConfig} className="min-h-[200px] w-full">
<LineChart data={parsedData}>
<ChartContainer
config={chartConfig}
className="max-h-[800px] min-h-[200px] w-full"
>
<BarChart data={parsedData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="week"
Expand All @@ -52,48 +106,55 @@ export function VeLordsRewardsChart({
}}
/>
<YAxis
yAxisId="apy"
dataKey="apy"
yAxisId="amount"
label={{
value: "% APY (4 year lock)",
value: "Total Lords Rewards",
angle: -90,
position: "insideLeft",
offset: 18,
}}
/>
<YAxis
yAxisId="total_amount"
yAxisId="apy"
orientation="right"
dataKey="total_amount"
allowDataOverflow={true}
dataKey="apy"
label={{
value: "Total Lords Rewards",
value: "% APY (4 year lock)",
angle: -90,
position: "outside",
offset: 25,
}}
/>
<ChartTooltip content={<ChartTooltipContent />} />
<ChartLegend content={<ChartLegendContent />} />
<Line
dataKey="total_amount"
type="monotone"
yAxisId="total_amount"
stroke="var(--color-total_amount)"
fill="var(--color-total_amount)"
radius={4}
activeDot={{ r: 8 }}
/>

{/* Stacked bars for each source */}
{Object.keys(sourceColors).map((source, index) => (
<Bar
key={source}
dataKey={`amounts.${source}`}
label={source}
stackId="rewards"
yAxisId="amount"
fill={sourceColors[source]}
stroke={sourceColors[source]}
radius={
index === Object.keys(sourceColors).length - 1
? [4, 4, 0, 0]
: [0, 0, 0, 0]
}
/>
))}

<Line
dataKey="apy"
type="monotone"
yAxisId="apy"
fill="var(--color-apy)"
stroke="var(--color-apy)"
radius={4}
fill="var(--color-apy)"
activeDot={{ r: 8 }}
/>
</LineChart>
</BarChart>
</ChartContainer>
);
}
Loading
Loading