Skip to content

Commit

Permalink
Merge pull request #66 from melnikga/feat/token-transfers-tab
Browse files Browse the repository at this point in the history
Contract page token transfers - Issue #40
  • Loading branch information
saimeunt authored Aug 9, 2024
2 parents dc6eaae + 39e8574 commit b79be7e
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 6 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dev": "next dev --turbo",
"build": "next build",
"start": "next start",
"prettier": "prettier --write \"src/**/*.{ts,tsx}\"",
"prettier": "prettier --write \"src/**/*.{ts,tsx}",
"lint": "next lint",
"prisma:generate": "prisma generate",
"prisma:db:push2": ". .env.local && export DATABASE_URL && prisma db push",
Expand Down
20 changes: 17 additions & 3 deletions src/app/address/[address]/token-transfers/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import { Address } from "viem";
import AddressTokenTransfers from "@/components/pages/address/address-token-transfers";
import { getLatestTransferEvents } from "@/lib/fetch-data";

const AddressTokenTransfersPage = ({

const AddressTokenTransfersPage = async ({
params: { address },
}: {
params: { address: string };
}) => <AddressTokenTransfers address={address as Address} />;
params: { address: Address };
}) => {
let transferEvents;
try {
transferEvents = await getLatestTransferEvents(address);
console.log("Transfer:", transferEvents);
} catch (error) {
console.error("Error Transfer:", error);
}
return(
<AddressTokenTransfers address={address as Address} erc20Transfers={transferEvents}
/>
)
};

export default AddressTokenTransfersPage;
118 changes: 117 additions & 1 deletion src/components/pages/address/address-token-transfers.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,127 @@
"use client";
import { Address } from "viem";
import { Card, CardHeader, CardContent } from "@/components/ui/card";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import TxMethodBadge from "@/components/lib/tx-method-badge";


interface TokenInfo {
address: string;
decimals: number;
}

interface ERC20Transfer {
transactionHash: string;
method: string;
block: number;
age: string;
from: string;
to: string;
amount: string;
token: TokenInfo;
type: 'ERC20';
}

interface TransferEventsResponse {
transfers: ERC20Transfer[];
page: number;
limit: number;
}



const AddressTokenTransfers = ({ address, erc20Transfers }: { address: Address, erc20Transfers: TransferEventsResponse | undefined }) => {


const AddressTokenTransfers = ({ address }: { address: Address }) => {
return (
<Card>
<CardHeader>Latest 25 ERC-20 Token Transfers Events</CardHeader>
<CardContent>TOKEN TRANSFERS</CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>Transaction Hash</TableHead>
<TableHead>Method</TableHead>
<TableHead>Block</TableHead>
<TableHead>Age</TableHead>
<TableHead>From</TableHead>
<TableHead>To</TableHead>
<TableHead>Amount</TableHead>
<TableHead>Token</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TooltipProvider>
{erc20Transfers && erc20Transfers?.transfers?.map((item,i)=>{
return(
<TableRow key={i}>
<TableCell>
<Tooltip
delayDuration={100}>
<TooltipTrigger>
{item.transactionHash.slice(0,12)}...
</TooltipTrigger>
<TooltipContent>
{item.transactionHash}
</TooltipContent>
</Tooltip>
</TableCell>
<TableCell>
<TxMethodBadge
selector={item.method}
signature={""}
/>
</TableCell>
<TableCell>
{item.block}
</TableCell>
<TableCell>
{item.age}
</TableCell>
<TableCell>
<Tooltip
delayDuration={100}
>
<TooltipTrigger>
{item.from.slice(0,11)}...{item.from.slice(-9)}
</TooltipTrigger>
<TooltipContent>
{item.from}
</TooltipContent>
</Tooltip>
</TableCell>
<TableCell>
<Tooltip
delayDuration={100}
>
<TooltipTrigger>
{item.to.slice(0,11)}...{item.to.slice(-9)}
</TooltipTrigger>
<TooltipContent>
{item.to}
</TooltipContent>
</Tooltip>

</TableCell>
<TableCell>
{item.amount}
</TableCell>
<TableCell>
{item.token.address.slice(0,11)}...{item.token.address.slice(-9)}
</TableCell>
</TableRow>
)
})}
</TooltipProvider>

</TableBody>
</Table>
</Card>
);
};
Expand Down
68 changes: 67 additions & 1 deletion src/lib/fetch-data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { subDays, formatISO } from "date-fns";
import { Hash } from "viem";
import { Address, formatUnits, Hash } from "viem";
import { formatDistanceToNow } from 'date-fns';
import { formatEther } from "viem";
import {
extractTransactionDepositedLogs,
getL2TransactionHash,
Expand All @@ -8,6 +10,9 @@ import { TransactionEnqueued } from "@/lib/types";
import { l1PublicClient } from "@/lib/chains";
import portal from "@/lib/contracts/portal/contract";
import l1CrossDomainMessenger from "@/lib/contracts/l1-cross-domain-messenger/contract";
import { loadFunctions } from "@/lib/signatures";
import { prisma } from "./prisma";
import { formatTimestamp } from "./utils";

// export const fetchLatestBlocks = async (start: bigint): Promise<Block[]> => {
// const blocksPerPage = BigInt(process.env.NEXT_PUBLIC_BLOCKS_PER_PAGE);
Expand Down Expand Up @@ -138,3 +143,64 @@ export const fetchTokensPrices = async () => {
op: { today: Number(opPriceToday), yesterday: Number(opPriceYesterday) },
};
};


export async function getLatestTransferEvents(
contractAddress: Address,
page: number = 1,
limit: number = 100
) {
console.log(contractAddress);
const skip = (page - 1) * limit;

try {
const erc20Transfers = await prisma.erc20Transfer.findMany({
where: {
OR: [
{ from: contractAddress },
{ to: contractAddress }
]
},
orderBy: { transactionHash: 'desc' },
take: limit,
skip: skip,
include: {
receipt: {
include: {
transaction: {
include: {
block: true,
},
},
},
},
},
});

const allTransfers = await Promise.all(erc20Transfers.map(async t => {
return {
transactionHash: t.transactionHash,
method: t.receipt.transaction.input.slice(0, 10),
block: Number(t.receipt.transaction.blockNumber),
age: formatTimestamp(t.receipt.transaction.block.timestamp).distance,
from: t.from,
to: t.to,
amount: formatUnits(BigInt(t.value), t.decimals),
token: {
address: t.address,
decimals: t.decimals,
},
type: 'ERC20' as const,
};
}));

return {
transfers: allTransfers,
page,
limit,
};
} catch (error) {
console.error("Error fetching token transfers:", error);
throw error;
}
}

0 comments on commit b79be7e

Please sign in to comment.