From f441f48770db67424f4e899aa5a437e984b8e927 Mon Sep 17 00:00:00 2001 From: Gustavo Kuhl Date: Fri, 1 Nov 2024 00:00:05 -0300 Subject: [PATCH 1/2] feat: update treasure endpoint --- .env.development | 20 +++++----- components/FarcasterIcon.tsx | 13 +++++++ components/Navbar.tsx | 60 ++++++----------------------- constants/addresses.ts | 4 ++ hooks/fetch/useTreasuryBalance.tsx | 3 +- pages/api/prices.ts | 62 ++++++++++++++++++++++++++++++ pages/api/treasury/[address].tsx | 50 ++++++++++++++++++++++-- pages/vote/index.tsx | 4 +- 8 files changed, 152 insertions(+), 64 deletions(-) create mode 100644 components/FarcasterIcon.tsx create mode 100644 pages/api/prices.ts diff --git a/.env.development b/.env.development index d5de11e..d7305b3 100644 --- a/.env.development +++ b/.env.development @@ -3,18 +3,18 @@ NEXT_PUBLIC_IPFS_GATEWAY="nxHSFa1jQsiF7IHeXWH-gXCY3LDLlZ7Run3aZXZc8DRCfQz4J4a94z NEXT_PUBLIC_TOKEN_NETWORK="8453" # Gnars -# NEXT_PUBLIC_NFT="0x880fb3cf5c6cc2d7dfc13a993e839a9411200c17" -# NEXT_PUBLIC_METADATA="0xdc9799d424ebfdcf5310f3bad3ddcce3931d4b58" -# NEXT_PUBLIC_AUCTION="0x494eaa55ecf6310658b8fc004b0888dcb698097f" -# NEXT_PUBLIC_TREASURY="0x72ad986ebac0246d2b3c565ab2a1ce3a14ce6f88" -# NEXT_PUBLIC_GOVERNOR="0x3dd4e53a232b7b715c9ae455f4e732465ed71b4c" +NEXT_PUBLIC_NFT="0x880fb3cf5c6cc2d7dfc13a993e839a9411200c17" +NEXT_PUBLIC_METADATA="0xdc9799d424ebfdcf5310f3bad3ddcce3931d4b58" +NEXT_PUBLIC_AUCTION="0x494eaa55ecf6310658b8fc004b0888dcb698097f" +NEXT_PUBLIC_TREASURY="0x72ad986ebac0246d2b3c565ab2a1ce3a14ce6f88" +NEXT_PUBLIC_GOVERNOR="0x3dd4e53a232b7b715c9ae455f4e732465ed71b4c" # HackerDao -NEXT_PUBLIC_NFT="0x6940100C44D214cD1570b394A1C42949C3eB820d" -NEXT_PUBLIC_AUCTION="0x1ef59b5276466b99d2f6600ffeaf3ccefea001ab" -NEXT_PUBLIC_GOVERNOR="0x7c4c33efe412f06f83278acafc16b435be904b03" -NEXT_PUBLIC_TREASURY="0x7c27601741cbc96b66766d499c15b688abeefcca" -NEXT_PUBLIC_METADATA="0xaf2273eb279a37654a22ebf4c6bfec3366e9e3a3" +# NEXT_PUBLIC_NFT="0x6940100C44D214cD1570b394A1C42949C3eB820d" +# NEXT_PUBLIC_AUCTION="0x1ef59b5276466b99d2f6600ffeaf3ccefea001ab" +# NEXT_PUBLIC_GOVERNOR="0x7c4c33efe412f06f83278acafc16b435be904b03" +# NEXT_PUBLIC_TREASURY="0x7c27601741cbc96b66766d499c15b688abeefcca" +# NEXT_PUBLIC_METADATA="0xaf2273eb279a37654a22ebf4c6bfec3366e9e3a3" # Skatehive # NEXT_PUBLIC_NFT="0xfe10d3ce1b0f090935670368ec6de00d8d965523" diff --git a/components/FarcasterIcon.tsx b/components/FarcasterIcon.tsx new file mode 100644 index 0000000..3cfedac --- /dev/null +++ b/components/FarcasterIcon.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +function FarcasterIcon({ width, height, color }: { width?: number, height?: number, color?: string }) { + return ( + + + + + + ); +} + +export default FarcasterIcon; diff --git a/components/Navbar.tsx b/components/Navbar.tsx index 330415f..f38af70 100644 --- a/components/Navbar.tsx +++ b/components/Navbar.tsx @@ -16,6 +16,8 @@ import { useState } from "react"; import { useBalance } from "wagmi"; +import FarcasterIcon from "./FarcasterIcon"; +import { TokenData } from "../pages/api/treasury/[address]"; function Navbar() { return ( @@ -124,51 +126,20 @@ function NavbarItem(props: NavbarItemProps) { function TreasureBoxItem() { const [treasureBalance, setTreasureBalance] = useState(0); - const { data: usdcData } = useBalance({ - address: DAO_ADDRESS.treasury, - token: USDC_ADDRESS, - }); - const { data: senditData } = useBalance({ - address: DAO_ADDRESS.treasury, - token: BASE_SENDIT_TOKEN_ADDRESS, - }); - const { data: wethData } = useBalance({ - address: DAO_ADDRESS.treasury, - token: BASE_WETH_TOKEN_ADDRESS, - }); - const { data: ethData } = useBalance({ - address: DAO_ADDRESS.treasury, - }); - useEffect(() => { - async function fetchPrices() { + async function fetchTreasureBalance() { try { - const response = await fetch(`https://api.coingecko.com/api/v3/simple/price?ids=ethereum,sendit&vs_currencies=usd`); - const prices = await response.json(); - - const ethPrice = prices.ethereum.usd; - const senditPrice = prices.sendit.usd; - - const usdcAmount = Number(usdcData?.value) / 10 ** Number(usdcData?.decimals); - const ethAmount = Number(ethData?.value) / 10 ** Number(ethData?.decimals); - const senditAmount = Number(senditData?.value) / 10 ** Number(senditData?.decimals); - const wethAmount = Number(wethData?.value) / 10 ** Number(wethData?.decimals); - - const usdcBalance = usdcAmount; // Assuming USDC is already in USD - const ethBalance = ethAmount * ethPrice; - const wethBalance = wethAmount * ethPrice; - const senditBalance = senditAmount * senditPrice; - - const totalBalance = usdcBalance + ethBalance + senditBalance + wethBalance; - - setTreasureBalance(totalBalance); + const response = await fetch('/api/treasury/' + DAO_ADDRESS.treasury); + const data: { tokens: TokenData[] } = await response.json(); + console.log({data}) + // setTreasureBalance(data.totalBalance); } catch (error) { - console.error("Failed to fetch prices:", error); + console.error("Failed to fetch treasure balance:", error); } } - fetchPrices(); - }, [usdcData, senditData, ethData]); + fetchTreasureBalance(); + }, []); return ( @@ -185,13 +156,4 @@ function TreasureBoxItem() { ); } -export default Navbar; - - -function FarcasterIcon({ width, height, color }: { width?: number, height?: number, color?: string }) { - return ( - - - - ) -} \ No newline at end of file +export default Navbar; \ No newline at end of file diff --git a/constants/addresses.ts b/constants/addresses.ts index ca7735e..4312117 100644 --- a/constants/addresses.ts +++ b/constants/addresses.ts @@ -8,6 +8,10 @@ export const MANAGER_CONTRACT = { "7777777": "0x3ac0e64fe2931f8e082c6bb29283540de9b5371c", }[process.env.NEXT_PUBLIC_TOKEN_NETWORK ?? "1"]!; +export const BASE_USDC_TOKEN_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"; +export const BASE_SENDIT_TOKEN_ADDRESS = "0xBa5B9B2D2d06a9021EB3190ea5Fb0e02160839A4"; +export const BASE_WETH_TOKEN_ADDRESS = "0x4200000000000000000000000000000000000006"; + export const DAO_ADDRESS = { nft: process.env.NEXT_PUBLIC_NFT as `0x${string}` || "0x880fb3cf5c6cc2d7dfc13a993e839a9411200c17", metadata: process.env.NEXT_PUBLIC_METADATA as `0x${string}` || "0xdc9799d424ebfdcf5310f3bad3ddcce3931d4b58", diff --git a/hooks/fetch/useTreasuryBalance.tsx b/hooks/fetch/useTreasuryBalance.tsx index 611d7b9..f917c32 100644 --- a/hooks/fetch/useTreasuryBalance.tsx +++ b/hooks/fetch/useTreasuryBalance.tsx @@ -1,4 +1,5 @@ import { BigNumber } from "ethers"; +import { TokenData } from "pages/api/treasury/[address]"; import useSWR from "swr"; export const useTreasuryBalance = ({ @@ -6,7 +7,7 @@ export const useTreasuryBalance = ({ }: { treasuryContract?: string; }) => { - return useSWR( + return useSWR<{ tokens: TokenData, totalBalance: number }>( treasuryContract ? `/api/treasury/${treasuryContract}` : undefined ); }; diff --git a/pages/api/prices.ts b/pages/api/prices.ts new file mode 100644 index 0000000..5c2bc57 --- /dev/null +++ b/pages/api/prices.ts @@ -0,0 +1,62 @@ +import { NextApiRequest, NextApiResponse } from "next"; +import { + DAO_ADDRESS, + USDC_ADDRESS, + BASE_SENDIT_TOKEN_ADDRESS, + BASE_WETH_TOKEN_ADDRESS, +} from "constants/addresses"; +import { useBalance } from "wagmi"; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + try { + // const { data: usdcData } = useBalance({ + // address: DAO_ADDRESS.treasury, + // token: USDC_ADDRESS, + // }); + // const { data: senditData } = useBalance({ + // address: DAO_ADDRESS.treasury, + // token: BASE_SENDIT_TOKEN_ADDRESS, + // }); + // const { data: wethData } = useBalance({ + // address: DAO_ADDRESS.treasury, + // token: BASE_WETH_TOKEN_ADDRESS, + // }); + // const { data: ethData } = useBalance({ + // address: DAO_ADDRESS.treasury, + // }); + + // const response = await fetch(`https://api.coingecko.com/api/v3/simple/price?ids=ethereum,sendit&vs_currencies=usd`); + // const prices = await response.json(); + + // const ethPrice = prices.ethereum.usd; + // const senditPrice = prices.sendit.usd; + + // const usdcAmount = Number(usdcData?.value) / 10 ** Number(usdcData?.decimals); + // const ethAmount = Number(ethData?.value) / 10 ** Number(ethData?.decimals); + // const senditAmount = Number(senditData?.value) / 10 ** Number(senditData?.decimals); + // const wethAmount = Number(wethData?.value) / 10 ** Number(wethData?.decimals); + + // const usdcBalance = usdcAmount; // Assuming USDC is already in USD + // const ethBalance = ethAmount * ethPrice; + // const wethBalance = wethAmount * ethPrice; + // const senditBalance = senditAmount * senditPrice; + + // const totalBalance = usdcBalance + ethBalance + senditBalance + wethBalance; + + // res.status(200).json({ totalBalance }); + + const res = await fetch( + `https://pioneers.dev/api/v1/portfolio/${DAO_ADDRESS.treasury}` + ); + const data = await res.json(); + + console.log(data); + // console.dir({ data }, { depth: null, colors: true }); + } catch (error) { + console.error("Failed to fetch prices:", error); + res.status(500).json({ error: "Failed to fetch prices" }); + } +} diff --git a/pages/api/treasury/[address].tsx b/pages/api/treasury/[address].tsx index e33e8e1..8cbb545 100644 --- a/pages/api/treasury/[address].tsx +++ b/pages/api/treasury/[address].tsx @@ -1,16 +1,60 @@ +import { BASE_SENDIT_TOKEN_ADDRESS, BASE_USDC_TOKEN_ADDRESS, BASE_WETH_TOKEN_ADDRESS } from "constants/addresses"; import { NextApiRequest, NextApiResponse } from "next"; -import DefaultProvider from "utils/DefaultProvider"; + +export interface Token { + address: string; + network: string; + label: string; + name: string; + symbol: string; + decimals: string; + verified: boolean; + price: string; + balance: number; + balanceUSD: number; + balanceRaw: string; +} + +export interface TokenData { + key: string; + address: string; + network: string; + updatedAt: string; + token: Token; + networkId: string; + assetCaip: string; +} + +const TOKEN_ADDRESSES = [ + BASE_USDC_TOKEN_ADDRESS.toLowerCase(), + BASE_SENDIT_TOKEN_ADDRESS.toLowerCase(), + BASE_WETH_TOKEN_ADDRESS.toLowerCase() +]; const handler = async (req: NextApiRequest, res: NextApiResponse) => { const { address } = req.query; - const treasuryBalance = await DefaultProvider.getBalance(address as string); + + const fetchRes = await fetch( + `https://pioneers.dev/api/v1/portfolio/${address as string}` + ); + const data: { tokens: TokenData[], totalBalanceUsdTokens: number } = await fetchRes.json(); + + console.log({data}) + + const filteredTokens = data.tokens.filter((i: TokenData) => + TOKEN_ADDRESSES.includes(i.token.address) + ); const ONE_DAY_IN_SECONDS = 60 * 60 * 24; res.setHeader( "Cache-Control", `s-maxage=60, stale-while-revalidate=${ONE_DAY_IN_SECONDS}` ); - res.send(treasuryBalance); + + res.send({ + tokens: filteredTokens, + totalBalance: data.totalBalanceUsdTokens, + }); }; export default handler; diff --git a/pages/vote/index.tsx b/pages/vote/index.tsx index 6f113e8..8ac33d8 100644 --- a/pages/vote/index.tsx +++ b/pages/vote/index.tsx @@ -91,7 +91,9 @@ export default function Vote({
Treasury
- Ξ {treasuryBalance ? formatTreasuryBalance(treasuryBalance) : "0"} + 117k USD + {/* Ξ {treasuryBalance ? formatTreasuryBalance(treasuryBalance) : "0"} + 117k USD */} + Total USD value: {treasuryBalance?.totalBalance.toFixed(2)} USD +
From 7797b8f98e3ec1bbf45d1574a19accc9516310ff Mon Sep 17 00:00:00 2001 From: Gustavo Kuhl Date: Fri, 1 Nov 2024 00:26:32 -0300 Subject: [PATCH 2/2] style: update treasury viewer --- components/DAO/Transaction.tsx | 2 +- hooks/fetch/useTreasuryBalance.tsx | 2 +- pages/vote/index.tsx | 29 +++++++++++++++++++++++------ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/components/DAO/Transaction.tsx b/components/DAO/Transaction.tsx index 6ef872d..9fbc6fa 100644 --- a/components/DAO/Transaction.tsx +++ b/components/DAO/Transaction.tsx @@ -144,7 +144,7 @@ function TokenValueRender({ address, value }: { address: string, value: bigint } return null; } -function TokenDataRender({ address }: { address: string }) { +export function TokenDataRender({ address }: { address: string }) { if (address === BASE_USDC_TOKEN_ADDRESS) { return (
diff --git a/hooks/fetch/useTreasuryBalance.tsx b/hooks/fetch/useTreasuryBalance.tsx index f917c32..18f79e4 100644 --- a/hooks/fetch/useTreasuryBalance.tsx +++ b/hooks/fetch/useTreasuryBalance.tsx @@ -7,7 +7,7 @@ export const useTreasuryBalance = ({ }: { treasuryContract?: string; }) => { - return useSWR<{ tokens: TokenData, totalBalance: number }>( + return useSWR<{ tokens: TokenData[], totalBalance: number }>( treasuryContract ? `/api/treasury/${treasuryContract}` : undefined ); }; diff --git a/pages/vote/index.tsx b/pages/vote/index.tsx index 8ac33d8..1b480b0 100644 --- a/pages/vote/index.tsx +++ b/pages/vote/index.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; import Layout from "@/components/Layout"; import { Proposal } from "@/services/nouns-builder/governor"; -import { TOKEN_CONTRACT } from "constants/addresses"; +import { TOKEN_CONTRACT, BASE_USDC_TOKEN_ADDRESS, BASE_SENDIT_TOKEN_ADDRESS, BASE_WETH_TOKEN_ADDRESS } from "constants/addresses"; import Link from "next/link"; import { useDAOAddresses, useGetAllProposals, useTreasuryBalance } from "hooks"; import { getProposalName } from "@/utils/getProposalName"; @@ -17,6 +17,7 @@ import { useUserVotes } from "@/hooks/fetch/useUserVotes"; import { useCurrentThreshold } from "@/hooks/fetch/useCurrentThreshold"; import Loading from "@/components/Loading"; import { extractImageUrl } from "@/utils/getProposalImage"; +import { TokenDataRender } from "@/components/DAO/Transaction"; export const getStaticProps = async (): Promise< GetStaticPropsResult<{ @@ -58,6 +59,12 @@ export default function Vote({ const [selectedTab, setSelectedTab] = useState<"all" | "onboarding">("all"); + const tokenAddresses = [ + { address: BASE_USDC_TOKEN_ADDRESS, name: "USDC" }, + { address: BASE_SENDIT_TOKEN_ADDRESS, name: "SENDIT" }, + { address: BASE_WETH_TOKEN_ADDRESS, name: "WETH" }, + ]; + const getProposalNumber = (i: number) => { if (!proposals) return 0; return proposals.length - i; @@ -88,12 +95,23 @@ export default function Vote({ )}
-
+
Treasury
-
+ {/*
*/} {/* Ξ {treasuryBalance ? formatTreasuryBalance(treasuryBalance) : "0"} + 117k USD */} - Total USD value: {treasuryBalance?.totalBalance.toFixed(2)} USD - + {/* Total USD value: {treasuryBalance?.totalBalance.toFixed(2)} USD */} +
+ {treasuryBalance?.tokens.map((tokenData) => { + const token = tokenData.token + return ( +
+
+ {token.name} {token.balance} +
+
+ ) + })} + {/*
*/}
@@ -101,7 +119,6 @@ export default function Vote({ the long-term growth and prosperity of the project.
-
{/* Tab navigation */}