8000 NewTokens · leon-do/v3-launchpad-ui@73a3993 · GitHub
[go: up one dir, main page]

Skip to content

Commit

Permalink
NewTokens
Browse files Browse the repository at this point in the history
  • Loading branch information
leon-do committed Feb 20, 2025
1 parent f6050e8 commit 73a3993
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
NEXT_PUBLIC_CHAIN_ID=20314
NEXT_PUBLIC_CHAIN_SYMBOL="PEPU"
NEXT_PUBLIC_LAUNCHPAD_ADDRESS=0x0f85D54502cba5E334e1fE687aF677e8739cd9B7
NEXT_PUBLIC_LAUNCHPAD_ADDRESS=0x9a835051C3eCF16dC1168965B4cacA37e49Ee013
NEXT_PUBLIC_RPC_URL=https://rpc-pepe-unchained-test-ypyaeq1krb.t.conduit.xyz
NEXT_PUBLIC_EXPLORER_URL=https://explorer-pepe-unchained-test-ypyaeq1krb.t.conduit.xyz
26 changes: 26 additions & 0 deletions src/abis/launchpadAbi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,25 @@ export const launchpadAbi = [
name: "OwnableUnauthorizedAccount",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "_token",
type: "address",
},
{
indexed: false,
internalType: "string",
name: "_tokenURI",
type: "string",
},
],
name: "LaunchToken",
type: "event",
},
{
anonymous: false,
inputs: [
Expand Down Expand Up @@ -102,6 +121,13 @@ export const launchpadAbi = [
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [{ internalType: "uint256", name: "", type: "uint256" }],
name: "tokenIds",
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
stateMutability: "view",
type: "function",
},
{
inputs: [{ internalType: "address", name: "newOwner", type: "address" }],
name: "transferOwnership",
Expand Down
69 changes: 69 additions & 0 deletions src/components/NewTokens.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useEffect, useState } from "react";
import { getNewTokens } from "../utils/getNewTokens";
import { formatNumber } from "../utils/formatNumber";

export default function NewTokens() {
const [newTokens, setNewTokens] = useState<TokenInfo[]>([]);

useEffect(() => {
getNewTokens().then((newTokens) => {
setNewTokens(newTokens);
});
}, []);

return (
<>
<table>
<thead>
<tr>
<th>Name</th>
<th>Symbol</th>
<th>Price</th>
<th>Volume</th>
<th>1H</th>
<th>6H</th>
<th>24H</th>
<th>Liquidity</th>
<th>Market Cap</th>
<th>Trade</th>
</tr>
</thead>
<tbody>
{newTokens.map((token) => (
<tr>
<td>{token.baseToken.name}</td>
<td>{token.baseToken.symbol}</td>
<td>${formatNumber(token.priceUsd)}</td>
<td>{formatNumber(token.volume.h24)}</td>
<td>
{token.priceChange.h1
? formatNumber(token.priceChange.h1) + "%"
: ""}
</td>
<td>
{token.priceChange.h6
? formatNumber(token.priceChange.h6) + "%"
: ""}
</td>
<td>
{token.priceChange.h24
? formatNumber(token.priceChange.h24) + "%"
: ""}
</td>
<td>{formatNumber(token.liquidity.usd)}</td>
<td>{formatNumber(token.marketCap)}</td>
<td>
<a
href={`https://dexscreener.com/base/${token.baseToken.address}`}
target="_blank"
>
Buy
</a>
</td>
</tr>
))}
</tbody>
</table>
</>
);
}
2 changes: 2 additions & 0 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { NextPage } from "next";
import Head from "next/head";
import Link from "next/link";
import NewTokens from "../components/NewTokens";

const Home: NextPage = () => {
return (
Expand All @@ -16,6 +17,7 @@ const Home: NextPage = () => {
<h1>HomePage</h1>
<button>CreateButton</button>
</Link>
<NewTokens />
</main>
</div>
);
Expand Down
35 changes: 35 additions & 0 deletions src/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,38 @@ interface TokenURI {
discord?: string;
telegram?: string;
}

interface TokenURIs {
[key: `0x${string}`]: TokenURI;
}

interface TokenInfo {
chainId: string;
dexId: string;
url: string;
pairAddress: string;
priceNative: string;
priceUsd: string;
fdv: number;
marketCap: number;
pairCreatedAt: number;
labels: string[];
volume: Record<string, number>;
priceChange: Record<string, number>;
baseToken: Token;
quoteToken: Token;
liquidity: {
usd: number;
base: number;
quote: number;
};
boosts: {
active: number;
};
txns: Record<string, { buys: number; sells: number; }>;
info: {
imageUrl: string;
websites: { url: string }[];
socials: { platform: string; handle: string }[];
};
}
10 changes: 10 additions & 0 deletions src/utils/formatNumber.ts
8000
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function formatNumber(num: number | string): string {
const value = Number(num); // Ensure the input is a number
if (value >= 1_000_000) {
return (value / 1_000_000).toFixed(1) + "M"; // Converts to millions
} else if (value >= 1_000) {
return (value / 1_000).toFixed(1) + "K"; // Converts to thousands
} else {
return value.toFixed(2); // If it's less than 1000, return the number with 2 decimals
}
}
55 changes: 55 additions & 0 deletions src/utils/getNewTokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
export async function getNewTokens(): Promise<TokenInfo[]> {
const subgraphUrl =
"https://gateway.thegraph.com/api/1124160e294feb0810e9eab14d14904e/subgraphs/id/GqzP4Xaehti8KSfQmv3ZctFSjnSUYZ4En5NRsiTbvZpz";

const positionQuery = `
query GetPositions {
positions(
# where: {owner: "${process.env.NEXT_PUBLIC_LAUNCHPAD_ADDRESS}"}
first: 1000
) {
id
token1 {
name
id
}
token0 {
name
id
}
}
}
`;
const positions = await fetch(subgraphUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({ query: positionQuery }),
})
.then((res) => res.json())
.then((res) => res.data.positions);

// sort by id desc and filter where token0.name contains "wrapped"
const filteredTokens = positions
.sort((a: any, b: any) => b.id - a.id)
.map(
(position: {
token0: { name: string; id: string };
token1: { name: string; id: string };
}) => {
return position.token0.name.toLowerCase().includes("wrapped")
? position.token1.id
: position.token0.id;
}
);

const dexScreenerUrl = `https://api.dexscreener.com/tokens/v1/base/${Array.from(
new Set(filteredTokens)
)}`;
const tokenInfo: TokenInfo[] = await fetch(dexScreenerUrl).then((res) =>
res.json()
);
return tokenInfo;
}
14 changes: 0 additions & 14 deletions src/utils/getTokenUri.ts

This file was deleted.

20 changes: 20 additions & 0 deletions src/utils/getTokenUris.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { publicClient } from "../wagmi";
import { launchpadAbi } from "../abis/launchpadAbi";

export async function getTokenUris(): Promise<TokenURIs> {
// get all logs emitted from launchpad
const logs: any = await publicClient.getLogs({
address: process.env.NEXT_PUBLIC_LAUNCHPAD_ADDRESS as `0x${string}`,
event: launchpadAbi[3] as any,
fromBlock: BigInt(0),
toBlock: "latest",
});
// map token address to TokenURI
const tokenUris: TokenURIs = {};
logs.forEach((log: any) => {
tokenUris[log.args._token] = JSON.parse(
atob(log.args._tokenURI.split(",")[1])
);
});
return tokenUris;
}

0 comments on commit 73a3993

Please sign in to comment.
0