From 8f07aae928d3da87b2d499495073879f6d1e5c84 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Mon, 16 Mar 2026 09:57:49 +0000 Subject: [PATCH 1/2] Fix MetaMask gas estimation failures and deadline hydration mismatch - Set explicit gas limits on donate (150k), mint (2M), burn (2M) to bypass MetaMask's broken gas estimation on Base Sepolia - Fix DeadlineCountdown hydration mismatch: render "--:--:--" on server, start countdown only after client mount Co-Authored-By: Claude Opus 4.6 --- src/components/DeadlineCountdown.tsx | 13 ++++++++++++- src/components/DonateWidget.tsx | 1 + src/components/TradingWidget.tsx | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/components/DeadlineCountdown.tsx b/src/components/DeadlineCountdown.tsx index 32ab7c14..3d51af33 100644 --- a/src/components/DeadlineCountdown.tsx +++ b/src/components/DeadlineCountdown.tsx @@ -5,15 +5,26 @@ import { useState, useEffect } from "react"; const DEADLINE_HOURS = 72; export function DeadlineCountdown({ lastPlotTime }: { lastPlotTime: string }) { - const [remaining, setRemaining] = useState(() => calcRemaining(lastPlotTime)); + const [remaining, setRemaining] = useState(null); useEffect(() => { + setRemaining(calcRemaining(lastPlotTime)); const interval = setInterval(() => { setRemaining(calcRemaining(lastPlotTime)); }, 1000); return () => clearInterval(interval); }, [lastPlotTime]); + if (remaining === null) { + return ( +
+ Deadline: + --:--:-- + remaining +
+ ); + } + if (remaining <= 0) { return (
diff --git a/src/components/DonateWidget.tsx b/src/components/DonateWidget.tsx index 28475abd..247b8926 100644 --- a/src/components/DonateWidget.tsx +++ b/src/components/DonateWidget.tsx @@ -62,6 +62,7 @@ export function DonateWidget({ storylineId }: DonateWidgetProps) { abi: storyFactoryAbi, functionName: "donate", args: [BigInt(storylineId), parsedAmount], + gas: BigInt(150_000), }); setTxHash(hash); diff --git a/src/components/TradingWidget.tsx b/src/components/TradingWidget.tsx index 8a463a72..4d26b9a8 100644 --- a/src/components/TradingWidget.tsx +++ b/src/components/TradingWidget.tsx @@ -92,6 +92,7 @@ export function TradingWidget({ tokenAddress }: { tokenAddress: Address }) { abi: mcv2BondAbi, functionName: "mint", args: [tokenAddress, parsedAmount, maxCost, address], + gas: BigInt(2_000_000), }); setTxHash(hash); setTxState("pending"); @@ -125,6 +126,7 @@ export function TradingWidget({ tokenAddress }: { tokenAddress: Address }) { abi: mcv2BondAbi, functionName: "burn", args: [tokenAddress, parsedAmount, minRefund, address], + gas: BigInt(2_000_000), }); setTxHash(hash); setTxState("pending"); From f4721b0307a895363be8fd083c99f05fe9924dbb Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Mon, 16 Mar 2026 10:04:37 +0000 Subject: [PATCH 2/2] [#153] Fix set-state-in-effect lint error in DeadlineCountdown Use lazy initializer for useState instead of synchronous setState inside useEffect to avoid cascading renders and satisfy the react-hooks/set-state-in-effect rule. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/DeadlineCountdown.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/DeadlineCountdown.tsx b/src/components/DeadlineCountdown.tsx index 3d51af33..871b4162 100644 --- a/src/components/DeadlineCountdown.tsx +++ b/src/components/DeadlineCountdown.tsx @@ -5,10 +5,11 @@ import { useState, useEffect } from "react"; const DEADLINE_HOURS = 72; export function DeadlineCountdown({ lastPlotTime }: { lastPlotTime: string }) { - const [remaining, setRemaining] = useState(null); + const [remaining, setRemaining] = useState(() => + typeof window === "undefined" ? null : calcRemaining(lastPlotTime), + ); useEffect(() => { - setRemaining(calcRemaining(lastPlotTime)); const interval = setInterval(() => { setRemaining(calcRemaining(lastPlotTime)); }, 1000);