Skip to content

Commit

Permalink
Merge pull request #55 from penumbra-zone/minimal-ibc-channel
Browse files Browse the repository at this point in the history
Basic page and API endpoint for querying a specific IBC Channel
  • Loading branch information
ejmg authored Jan 17, 2024
2 parents 073d8dd + fcd3ca5 commit 6dd3eb0
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 0 deletions.
120 changes: 120 additions & 0 deletions src/app/api/ibc/channel/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { type NextRequest } from "next/server";
import db from "@/lib/db";

export async function GET(req: NextRequest) {
console.log("SUCCESS: GET /api/ibc/channel");
try {
const url = new URL(req.url);
const channelIdParam = url.searchParams.get("q")?.trim() ?? "";
if (channelIdParam === "") {
throw new Error("No channel id provided.");
}
console.log(`Querying indexer for IBC Channel with id ${channelIdParam}.`);
const connectionId = await db.events.findFirstOrThrow({
select: {
attributes: {
select: {
key: true,
value: true,
},
where: {
key: {
equals: "connection_id",
},
},
},
},
where: {
AND: [
{
type: {
equals: "channel_open_init",
},
},
{
attributes: {
some: {
value: {
equals: channelIdParam,
},
},
},
},
],
},
});

console.log("Successfully queried connection_id for channel.", connectionId);

const clientId = await db.events.findFirstOrThrow({
select: {
attributes: {
select: {
key: true,
value: true,
},
where: {
key: {
equals: "client_id",
},
},
},
},
where: {
AND: [
{
type: {
equals: "connection_open_init",
},
},
{
attributes: {
some: {
value: {
equals: connectionId.attributes[0].value,
},
},
},
},
],
},
});

console.log("Successfully queried client_id for channel.", clientId);


// This will return the block id for the latest client_update event type for a given client_id.
const transactions = await db.events.findMany({
select: {
tx_results: {
select: {
tx_hash: true,
},
},
},
where: {
attributes: {
some: {
value: {
equals: channelIdParam,
},
},
},
},
orderBy: {
block_id: "desc",
},
take: 10,
});

const recentTransactions = transactions.map(({ tx_results: txResults }) => ({ "hash": txResults?.tx_hash }));

console.log("Successfully queried recent transactions for channel.", recentTransactions);

return new Response(JSON.stringify({ "connectionId": connectionId.attributes[0].value, "clientId": clientId.attributes[0].value, recentTransactions}));

} catch (error) {
console.error("GET request failed.", error);
return new Response("Could not query IBC Channel.", { status: 500 });
}
};
78 changes: 78 additions & 0 deletions src/app/ibc/channel/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"use client";

import { type FC } from "react";
import axios from "axios";
import { useQuery } from "@tanstack/react-query";
import Link from "next/link";

interface PageProps {
params: {
id: string,
}
}

const Page : FC<PageProps> = ({ params }) => {
const { id: channelId } = params;
const { data, isFetched, isError } = useQuery({
queryFn: async () => {
console.log(`Fetching: GET /api/ibc/channel/${channelId}`);
const { data } = await axios.get(`/api/ibc/channel?q=${channelId}`);
console.log("Fetched result:", data);
return data as { connectionId: string, clientId: string, recentTransactions: Array<{hash: string}>};
// TODO: enforce validation
// const result = IbcChannelValidator.safeParse(data);
},
queryKey: ["IbcChannel", channelId],
retry: false,
meta: {
errorMessage: "Failed to query IBC Channel by id. Please try again.",
},
});

if (isError) {
return (
<div className="py-5 flex justify-center">
<h1 className="text-4xl font-semibold">No results found.</h1>
</div>
);
}

return (
<div>
{isFetched ? (
<div className="flex flex-col justify-center w-full">
<h1 className="text-3xl mx-auto py-5 font-semibold">IBC Channel</h1>
{// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
data ? (
<div className="bg-white rounded-sm flex flex-wrap justify-between p-5 max-w-5xl ml-auto mr-auto gap-2">
<div className="flex justify-start w-full">
<p className="w-1/6">Channel ID</p>
<pre>{channelId}</pre>
</div>
<div className="flex justify-start w-full">
<p className="w-1/6">Client ID</p>
<Link href={`/ibc/client/${data.clientId}`} className="underline"><pre>{data.clientId}</pre></Link>
</div>
<div className="flex justify-start w-full">
<p className="w-1/6">Connection IDs</p>
<Link href={`/ibc/connection/${data.connectionId}`} className="underline"><pre>{data.connectionId}</pre></Link>
</div>
<div className="flex justify-start w-full">
<p className="w-1/6">Recent Transactions</p>
<div className="overflow-hidden">
{data.recentTransactions.map(({ hash }, i) => <Link href={`/transaction/${hash}`} key={i} className="underline"><pre>{hash}</pre></Link>)}
</div>
</div>
</div>
) : (
<p>No results</p>
)}
</div>
) : (
<p>loading...</p>
)}
</div>
);
};

export default Page;

0 comments on commit 6dd3eb0

Please sign in to comment.