Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b9f747b
Enhance Transaction Explorer with animated sections and improved load…
DangDuyLe Mar 25, 2025
0b8a459
Implement loading indicator for improved user experience in Transacti…
DangDuyLe Mar 25, 2025
c45b151
Enhance TradingChart and TradingViewLayout with data validation, load…
DangDuyLe Mar 25, 2025
a00f2f5
cors
TTMordred Mar 26, 2025
05cee24
Merge pull request #144 from TTMordred/Staking-(Done)
Woft257 Mar 26, 2025
9456792
Merge pull request #136 from TTMordred/branchcuadangduy
DangDuyLe Mar 26, 2025
710b031
Add remote patterns for Frontera Games and Cellula Life in next.confi…
TTMordred Mar 26, 2025
018d108
Enhance LazyImage component with improved error handling, fallback su…
TTMordred Mar 26, 2025
2ce4cdf
Merge branch 'main' of https://github.com/TTMordred/CryptoPath into n…
TTMordred Mar 26, 2025
6c605f8
Merge pull request #145 from TTMordred/nft_collection_2
TTMordred Mar 26, 2025
d0ab663
Refactor RevenueGraph to simplify time range handling and remove unus…
DangDuyLe Mar 26, 2025
656db8e
Merge pull request #146 from TTMordred/branchcuadangduy
DangDuyLe Mar 26, 2025
239808b
Enhance UI components with backdrop blur effect and update link routi…
HungPhan-0612 Mar 26, 2025
ef12db7
Add Search Function feature to LandingPage with updated UI and descri…
DangDuyLe Mar 26, 2025
bab7430
Merge pull request #147 from TTMordred/hungphanne
HungPhan-0612 Mar 26, 2025
463cb56
Update search functionality to include new search types and improve a…
HungPhan-0612 Mar 26, 2025
dad0027
rework home page
DangDuyLe Mar 26, 2025
6ff4ab4
Merge pull request #148 from TTMordred/hungphanne
HungPhan-0612 Mar 26, 2025
e956d7d
Remove commented-out code for Trending Projects & Partner Bar from La…
DangDuyLe Mar 26, 2025
0f2f84b
Add new dependencies: react-spring, react-countup, and swiper
DangDuyLe Mar 26, 2025
db97acb
Update ESLint configuration and refactor Swiper integration in Landin…
DangDuyLe Mar 26, 2025
ee9f893
Refactor cursor animation in LandingPage by replacing react-spring wi…
DangDuyLe Mar 26, 2025
9af6c91
Merge pull request #149 from TTMordred/branchcuadangduy
DangDuyLe Mar 26, 2025
0afe9d1
Reset loading and error states on new fetch in BlockTransactions, Blo…
HungPhan-0612 Mar 27, 2025
3262c69
Merge pull request #150 from TTMordred/hungphanne
HungPhan-0612 Mar 27, 2025
cdfd9b0
Add contract detection feature and display in WalletInfo component
HungPhan-0612 Mar 27, 2025
8444cfb
Merge pull request #151 from TTMordred/hungphanne
HungPhan-0612 Mar 27, 2025
fd5e609
Remove unnecessary gradient background from LandingPage component
HungPhan-0612 Mar 27, 2025
5081543
Merge pull request #152 from TTMordred/hungphanne
HungPhan-0612 Mar 27, 2025
40d1dbc
Update StakingCard component: change staking contract address and adj…
Woft257 Mar 27, 2025
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
165 changes: 165 additions & 0 deletions app/api/alchemy-iscontract/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import { NextResponse } from "next/server";

const ALCHEMY_API_KEY = process.env.ALCHEMY_API_KEY;
const ALCHEMY_API_URL = `https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`;

interface ContractData {
isContract: boolean;
contractInfo?: {
name: string;
symbol?: string;
tokenType?: 'ERC20' | 'ERC721' | 'ERC1155';
totalSupply?: string;
decimals?: number;
logo?: string;
holders?: number;
transactions?: number;
deployedAt?: string;
implementationAddress?: string;
verified: boolean;
};
}

export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const address = searchParams.get("address");

if (!address) {
return NextResponse.json(
{ error: "Address is required" },
{ status: 400 }
);
}

try {
// Check if address is a contract
const codeResponse = await fetch(ALCHEMY_API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'eth_getCode',
params: [address, 'latest']
})
});

const codeData = await codeResponse.json();
const isContract = codeData.result !== '0x';

if (!isContract) {
return NextResponse.json({ isContract: false });
}

// Check contract interfaces to determine type
const [erc721Response, erc1155Response] = await Promise.all([
// Check ERC721 interface
fetch(ALCHEMY_API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 2,
method: 'eth_call',
params: [{
to: address,
data: '0x01ffc9a780ac58cd00000000000000000000000000000000000000000000000000000000'
}, 'latest']
})
}),
// Check ERC1155 interface
fetch(ALCHEMY_API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 3,
method: 'eth_call',
params: [{
to: address,
data: '0x01ffc9a7d9b67a2600000000000000000000000000000000000000000000000000000000'
}, 'latest']
})
})
]);

const [erc721Data, erc1155Data] = await Promise.all([
erc721Response.json(),
erc1155Response.json()
]);

// Get token metadata
const metadataResponse = await fetch(ALCHEMY_API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 4,
method: 'alchemy_getTokenMetadata',
params: [address]
})
});

const metadataData = await metadataResponse.json();
const metadata = metadataData.result;

// Determine token type
let tokenType: 'ERC20' | 'ERC721' | 'ERC1155' | undefined;

if (erc721Data.result === '0x0000000000000000000000000000000000000000000000000000000000000001') {
tokenType = 'ERC721';
} else if (erc1155Data.result === '0x0000000000000000000000000000000000000000000000000000000000000001') {
tokenType = 'ERC1155';
} else if (metadata?.decimals !== undefined) {
tokenType = 'ERC20';
}

// Get deployment info
const deploymentResponse = await fetch(ALCHEMY_API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 5,
method: 'alchemy_getAssetTransfers',
params: [
{
fromBlock: "0x0",
toAddress: address,
category: ["external"],
withMetadata: true,
excludeZeroValue: true,
maxCount: "0x1"
}
]
})
});

const deploymentData = await deploymentResponse.json();
const deployment = deploymentData.result?.transfers?.[0];

const contractData: ContractData = {
isContract: true,
contractInfo: {
name: metadata?.name || "Unknown Contract",
symbol: metadata?.symbol,
tokenType,
totalSupply: metadata?.totalSupply,
decimals: metadata?.decimals,
logo: metadata?.logo,
holders: 0,
transactions: 0,
deployedAt: deployment?.metadata?.blockTimestamp,
verified: Boolean(metadata?.name),
}
};

return NextResponse.json(contractData);
} catch (error) {
console.error("Error detecting contract:", error);
return NextResponse.json(
{ error: "Failed to detect contract" },
{ status: 500 }
);
}
}
9 changes: 7 additions & 2 deletions app/block-txns/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ export default function BlockTransactions() {

useEffect(() => {
const fetchBlockData = async () => {
// Reset states when starting a new fetch
setLoading(true);
setError(null);
setBlockData(null);
setPage(1); // Reset pagination when new block is loaded

if (!blockNumber) {
setError("Block number is required");
setLoading(false);
Expand All @@ -82,7 +88,6 @@ export default function BlockTransactions() {
}
};

setLoading(true);
fetchBlockData();
}, [blockNumber]);

Expand Down Expand Up @@ -166,7 +171,7 @@ export default function BlockTransactions() {
</div>
</div>

<Card className="bg-transparent border-amber-500/20 shadow-xl hover:shadow-amber-500/10 transition-all duration-500 rounded-[10px]">
<Card className="bg-transparent border-amber-500/20 shadow-xl hover:shadow-amber-500/10 transition-all duration-500 rounded-[10px] backdrop-blur-sm">
<CardContent className="p-6">
{totalTransactions > 0 ? (
<>
Expand Down
45 changes: 34 additions & 11 deletions app/block/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
Loader2, Copy, ExternalLink,
Clock, Hash, ChevronUp,
Cpu, Fuel, Pickaxe,
Database, Layers
Database, Layers, ArrowLeft
} from "lucide-react";
import { toast } from "sonner";
import { format } from "date-fns";
Expand Down Expand Up @@ -54,6 +54,11 @@ export default function BlockDetails() {

useEffect(() => {
const fetchBlock = async () => {
// Reset states when starting a new fetch
setLoading(true);
setError(null);
setBlock(null);

if (!blockNumber) {
setError("Block number is required");
setLoading(false);
Expand All @@ -69,8 +74,11 @@ export default function BlockDetails() {
}

setBlock(data);
setError(null);
} catch (err) {
console.error("Error fetching block:", err);
setError(err instanceof Error ? err.message : "Failed to fetch block details");
setBlock(null);
} finally {
setLoading(false);
}
Expand Down Expand Up @@ -99,15 +107,30 @@ export default function BlockDetails() {

if (error || !block) {
return (
<div className="container mx-auto p-4">
<Card className="mt-8 border-red-500/50">
<CardContent className="p-6">
<div className="text-center text-red-500">
<p className="text-lg">{error || "Block not found"}</p>
</div>
</CardContent>
</Card>
</div>
<>
<ParticlesBackground />
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="container mx-auto p-4"
>
<Card className="mt-8 border-red-500/50">
<CardContent className="p-6">
<div className="text-center text-red-500">
<p className="text-lg">{error || "Block not found"}</p>
<Button
variant="ghost"
className="mt-4 text-amber-500 hover:text-amber-400"
onClick={() => router.back()}
>
<ArrowLeft className="h-4 w-4 mr-2" />
Go Back
</Button>
</div>
</CardContent>
</Card>
</motion.div>
</>
);
}

Expand All @@ -120,7 +143,7 @@ export default function BlockDetails() {
transition={{ duration: 0.5 }}
className="container mx-auto p-4"
>
<Card className="mt-8 bg-transparent border-amber-500/20 shadow-xl hover:shadow-amber-500/10 transition-all duration-500">
<Card className="mt-8 bg-transparent border-amber-500/20 shadow-xl hover:shadow-amber-500/10 transition-all duration-500 backdrop-blur-sm rounded-[10px]">
<CardContent className="p-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<InfoCard title="Block Number" icon={Layers}>
Expand Down
Loading