Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 18 additions & 1 deletion lib/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createPublicClient, http, fallback } from "viem";
import { createPublicClient, http, fallback, type Hex } from "viem";
import { base, baseSepolia } from "viem/chains";

const chainId = Number(process.env.NEXT_PUBLIC_CHAIN_ID || "84532");
Expand All @@ -20,3 +20,20 @@ export const publicClient = createPublicClient({
chain,
transport,
});

/**
* Fetch a transaction receipt with retries and backoff.
* Load-balanced RPC nodes may not have the receipt immediately after
* `waitForTransactionReceipt` completes on the client side.
*/
export async function getReceiptWithRetry(hash: Hex, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await publicClient.getTransactionReceipt({ hash });
} catch (err) {
if (attempt === maxAttempts) throw err;
await new Promise((r) => setTimeout(r, attempt * 1000));
}
}
throw new Error("unreachable");
}
6 changes: 3 additions & 3 deletions src/app/api/index/donation/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
import { type Hex, decodeEventLog, encodeEventTopics } from "viem";
import { publicClient } from "../../../../../lib/viem";
import { publicClient, getReceiptWithRetry } from "../../../../../lib/rpc";
import { createServerClient } from "../../../../../lib/supabase";
import {
storyFactoryAbi,
Expand All @@ -26,10 +26,10 @@ export async function POST(req: Request) {
return error("Missing or invalid txHash");
}

// 1. Fetch receipt
// 1. Fetch receipt (with retry for load-balanced RPC nodes)
let receipt;
try {
receipt = await publicClient.getTransactionReceipt({ hash: txHash });
receipt = await getReceiptWithRetry(txHash);
} catch {
return error("Failed to fetch transaction receipt", 502);
}
Expand Down
6 changes: 3 additions & 3 deletions src/app/api/index/plot/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
import { type Hex, decodeEventLog, encodeEventTopics } from "viem";
import { publicClient } from "../../../../../lib/viem";
import { publicClient, getReceiptWithRetry } from "../../../../../lib/rpc";
import { createServerClient } from "../../../../../lib/supabase";
import {
storyFactoryAbi,
Expand Down Expand Up @@ -31,10 +31,10 @@ export async function POST(req: Request) {
return error("Missing or invalid txHash");
}

// 1. Fetch receipt
// 1. Fetch receipt (with retry for load-balanced RPC nodes)
let receipt;
try {
receipt = await publicClient.getTransactionReceipt({ hash: txHash });
receipt = await getReceiptWithRetry(txHash);
} catch {
return error("Failed to fetch transaction receipt", 502);
}
Expand Down
6 changes: 3 additions & 3 deletions src/app/api/index/storyline/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
import { type Hex, decodeEventLog, encodeEventTopics } from "viem";
import { publicClient } from "../../../../../lib/viem";
import { publicClient, getReceiptWithRetry } from "../../../../../lib/rpc";
import { createServerClient } from "../../../../../lib/supabase";
import {
storyFactoryAbi,
Expand Down Expand Up @@ -32,10 +32,10 @@ export async function POST(req: Request) {
return error("Missing or invalid txHash");
}

// 1. Fetch receipt
// 1. Fetch receipt (with retry for load-balanced RPC nodes)
let receipt;
try {
receipt = await publicClient.getTransactionReceipt({ hash: txHash });
receipt = await getReceiptWithRetry(txHash);
} catch {
return error("Failed to fetch transaction receipt", 502);
}
Expand Down
Loading