From 1a27408d8e89b78f9c1bff39f80712c1a50b8c09 Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 25 Apr 2024 16:17:53 +0100 Subject: [PATCH 1/4] new --- pages/api/tokens.ts | 69 ++++++++++++ pages/dashboard/index.tsx | 13 +++ pages/dashboard/prospective.tsx | 188 ++++++++++++++++++++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 pages/api/tokens.ts create mode 100644 pages/dashboard/prospective.tsx diff --git a/pages/api/tokens.ts b/pages/api/tokens.ts new file mode 100644 index 00000000..44ad8d52 --- /dev/null +++ b/pages/api/tokens.ts @@ -0,0 +1,69 @@ +import type { NextApiRequest, NextApiResponse } from 'next' + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse, +) { + const { offset = 0 } = req.query + + // Check if the API key is defined or provide a default/fallback value + const apiKey = process.env.NEXT_PUBLIC_API_KEY || 'your-default-api-key' // Consider a fallback if environment variable might not be set + const options = { + method: 'GET', + headers: { + 'X-API-KEY': apiKey, + }, + } + + try { + // Fetch the initial list of tokens + const response = await fetch( + `https://public-api.birdeye.so/defi/tokenlist?sort_by=v24hUSD&sort_type=desc&offset=${offset}&limit=50`, + options, + ) + const tokenListResponse = await response.json() + const tokenList = tokenListResponse['data']['tokens'] + const filteredTokens = [] + + // Loop through each token to check additional criteria + for (const token of tokenList) { + const { address, v24hUSD } = token + if (v24hUSD > 50000) { + const now = new Date() + const nowInSeconds = Math.floor(now.getTime() / 1000) + const pastDate = new Date() + pastDate.setDate(pastDate.getDate() - 4) + pastDate.setMonth(pastDate.getMonth() - 1) + const pastDateInSeconds = Math.floor(pastDate.getTime() / 1000) + + // Fetch history for the token + const historyResponse = await fetch( + `https://public-api.birdeye.so/defi/history_price?address=${address}&address_type=token&type=1D&time_from=${pastDateInSeconds}&time_to=${nowInSeconds}`, + options, + ) + const historyData = await historyResponse.json() + + if (historyData['data']['items']?.length >= 35) { + const detailResponse = await fetch( + `https://public-api.birdeye.so/defi/token_overview?address=${address}`, + options, + ) + const tokenDetails = await detailResponse.json() + if ( + tokenDetails['data']['mc'] > 15000000 && + tokenDetails['data']['numberMarkets'] > 10 + ) { + // market cap greater than 1 mil + filteredTokens.push(tokenDetails['data']) + } + } + } + } + + // Return the filtered list of tokens + res.status(200).json(filteredTokens) + } catch (error) { + console.error('Failed to fetch tokens:', error) + res.status(500).json({ error: 'Failed to fetch tokens' }) + } +} diff --git a/pages/dashboard/index.tsx b/pages/dashboard/index.tsx index f1831d00..7a48e196 100644 --- a/pages/dashboard/index.tsx +++ b/pages/dashboard/index.tsx @@ -1380,6 +1380,19 @@ export const DashboardNavbar = () => { +
+ +

+ Prospective +

+ +
=> { + const res = await fetch(`/api/tokens?offset=${offset * 50}&limit=50`) + const data = await res.json() + return [...existingTokens, ...data] // Ensure the returned data conforms to Token[] +} + +const Prospective: NextPage = () => { + const banks = useBanks()['banks'] + const bankNames = banks.map((bank) => bank.name.toUpperCase()) + + // Generate headers from the first token entry if available + const [tokensList, setTokensList] = useState([]) + const [offset, setOffset] = useState(0) + const [loading, setLoading] = useState(false) + + useEffect(() => { + const initialFetch = async () => { + setLoading(true) + try { + const initialTokens: Token[] = await fetchTokens(0) + setTokensList(initialTokens) + } catch (error) { + console.error('Failed to fetch tokens:', error) + } finally { + setLoading(false) + } + } + initialFetch() + }, []) + + const handleShowMore = async () => { + setLoading(true) + try { + const newTokens = await fetchTokens(offset + 1, tokensList) + setTokensList(newTokens) + setOffset((prevOffset) => prevOffset + 1) + } catch (error) { + console.error('Failed to fetch more tokens:', error) + } + setLoading(false) + } + + const heads = useMemo(() => { + if (tokensList.length > 0) { + const allKeys = Object.keys(tokensList[0]) + const filteredKeys = allKeys.filter( + (key) => + ![ + 'symbol', + 'extensions', + 'lastTradeUnixTime', + 'uniqueWallet30m', + ].includes(key), + ) + return ['symbol', ...filteredKeys] + } + return [] + }, [tokensList]) + + return ( +
+ +
+
+

+ Hidden Gems to Prospect On +

+
+
+ + + + {heads.map((head, index) => ( + + ))} + + + + {tokensList.map((token: Token, idx) => ( + + window.open( + `https://birdeye.so/token/${token['address']}?chain=solana&tab=recentTrades`, + '_blank', + ) + } + > + {heads.map((head, valIdx) => { + if (head == 'symbol') { + token[head] = token[head]?.toUpperCase().toString() + } + return ( + + ) + })} + + ))} + +
+ {head} +
+
+
+ {head == 'logoURI' ? ( + <> + Token Logo{' '} + + ) : ( + <> + {token[head] ? token[head]?.toString() : 'N/A'} + + )} +
+
+
+
+ {loading && ( +
+ +
+ )} + +
+ Show More +
+
+
+ ) +} + +export default Prospective From f00a6f48b1350e7c3d0f5b2b2c208c457a46205b Mon Sep 17 00:00:00 2001 From: Finn Date: Sun, 28 Apr 2024 13:12:38 +0100 Subject: [PATCH 2/4] new --- pages/dashboard/prospective.tsx | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/pages/dashboard/prospective.tsx b/pages/dashboard/prospective.tsx index 9ab62a8b..27930d65 100644 --- a/pages/dashboard/prospective.tsx +++ b/pages/dashboard/prospective.tsx @@ -124,18 +124,15 @@ const Prospective: NextPage = () => { xBorder={valIdx != 0} key={valIdx} className={`!py-3 - ${ - valIdx === 0 - ? 'sticky left-0 z-10 bg-th-bkg-2' - : '' - } - ${ - valIdx === 0 && - bankNames.includes(token[head]) - ? 'bg-lime-200' - : '' - } - `} + ${ + valIdx === 0 + ? 'sticky left-0 z-10 ' + + (bankNames.includes(token[head]) + ? 'bg-lime-200' + : 'bg-th-bkg-2') + : '' + } + `} >
From 7cd57c63a9f59395beb7dbb246978835b1505117 Mon Sep 17 00:00:00 2001 From: Finn Date: Sun, 28 Apr 2024 13:18:15 +0100 Subject: [PATCH 3/4] new --- yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index d6c8d86d..9da184d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2577,7 +2577,7 @@ dependencies: "@solana/wallet-adapter-base" "^0.9.23" -"@solana/wallet-adapter-solflare@0.6.27", "@solana/wallet-adapter-solflare@^0.6.28": +"@solana/wallet-adapter-solflare@0.6.27": version "0.6.27" resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-solflare/-/wallet-adapter-solflare-0.6.27.tgz#49ba2dfecca4bee048e65d302216d1b732d7e39e" integrity sha512-MBBx9B1pI8ChCT70sgxrmeib1S7G9tRQzfMHqJPdGQ2jGtukY0Puzma2OBsIAsH5Aw9rUUUFZUK+8pzaE+mgAg== @@ -2588,7 +2588,7 @@ "@solflare-wallet/sdk" "^1.3.0" "@wallet-standard/wallet" "^1.0.1" -"@solana/wallet-adapter-solflare@0.6.28": +"@solana/wallet-adapter-solflare@0.6.28", "@solana/wallet-adapter-solflare@^0.6.28": version "0.6.28" resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-solflare/-/wallet-adapter-solflare-0.6.28.tgz#3de42a43220cca361050ebd1755078012a5b0fe2" integrity sha512-iiUQtuXp8p4OdruDawsm1dRRnzUCcsu+lKo8OezESskHtbmZw2Ifej0P99AbJbBAcBw7q4GPI6987Vh05Si5rw== From 6ddd38b2c0c87577aa549c6d7202df83b3d26529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Tue, 30 Apr 2024 01:28:42 +0200 Subject: [PATCH 4/4] fix env variable naming --- pages/api/tokens.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pages/api/tokens.ts b/pages/api/tokens.ts index 44ad8d52..56a5e0f9 100644 --- a/pages/api/tokens.ts +++ b/pages/api/tokens.ts @@ -7,7 +7,8 @@ export default async function handler( const { offset = 0 } = req.query // Check if the API key is defined or provide a default/fallback value - const apiKey = process.env.NEXT_PUBLIC_API_KEY || 'your-default-api-key' // Consider a fallback if environment variable might not be set + const apiKey = + process.env.NEXT_PUBLIC_BIRDEYE_API_KEY || 'your-default-api-key' // Consider a fallback if environment variable might not be set const options = { method: 'GET', headers: { @@ -22,6 +23,7 @@ export default async function handler( options, ) const tokenListResponse = await response.json() + const tokenList = tokenListResponse['data']['tokens'] const filteredTokens = []