Skip to content

Markee integration#811

Merged
Corantin merged 30 commits intomobile-viewfrom
Markee-Integration
Feb 25, 2026
Merged

Markee integration#811
Corantin merged 30 commits intomobile-viewfrom
Markee-Integration

Conversation

@Corantin
Copy link
Contributor

@Corantin Corantin commented Feb 19, 2026

This pull request introduces a new interactive "Markee sign" feature to the Gardens client page, allowing users to view and update a message displayed on the page by paying ETH. The feature integrates with the Markee protocol, fetches current sign data from a subgraph, and provides a modal for users to submit a new message. Minor code cleanups were also made.

Markee sign feature integration:

  • Added the new MarkeeSign component to the Gardens client page, displaying the current sign message and ETH badge, and allowing users to open a modal to update the sign. (apps/web/app/(app)/gardens/client-page.tsx, [1] [2]
  • Implemented the MarkeeSign component, which fetches the current sign message, top dawg ETH amount, and minimum price from the Markee subgraph, displays them, and handles modal opening/closing and data refresh after successful updates. (apps/web/components/MarkeeSign.tsx, apps/web/components/MarkeeSign.tsxR1-R126)
  • Added the MarkeeModal component, providing a form for users to submit a new sign message and ETH payment, with validation, transaction handling, and success/error feedback. (apps/web/components/MarkeeModal.tsx, apps/web/components/MarkeeModal.tsxR1-R270)

Code cleanup:

  • Removed outdated comments related to council safe support and Protopian transfer logic in the Gardens client page code. (apps/web/app/(app)/gardens/client-page.tsx, [1] [2]

Copilot AI review requested due to automatic review settings February 19, 2026 02:30
@vercel
Copy link

vercel bot commented Feb 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gardens-v2 Error Error Feb 25, 2026 5:46am

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Markee-powered “Gardens Sign” UI to the Gardens landing page, fetching the current top Markee message from a subgraph and allowing users to submit a new message via an on-chain transaction.

Changes:

  • Introduces MarkeeSign component to fetch/display the current Markee message + top amount.
  • Introduces MarkeeModal component to submit a new Markee message via createMarkee on Base.
  • Embeds MarkeeSign into the Gardens client page header and adjusts spacing.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 11 comments.

File Description
apps/web/components/MarkeeSign.tsx New sign UI; fetches Markee data from The Graph and opens the edit modal.
apps/web/components/MarkeeModal.tsx New modal for composing/submitting a message and sending a contract transaction.
apps/web/app/(app)/gardens/client-page.tsx Adds the sign to the header and tweaks layout/imports.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +71 to +85
const validate = () => {
if (!message.trim()) {
setInputError("Message cannot be empty.");
return false;
}
if (!ethAmount || isNaN(parseFloat(ethAmount)) || parseFloat(ethAmount) <= 0) {
setInputError("Enter a valid ETH amount.");
return false;
}
if (minBeat > BigInt(0) && parseEther(ethAmount) < minBeat) {
setInputError(
`You need at least ${minBeatEth.toFixed(4)} ETH to become top dawg.`,
);
return false;
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate() calls parseEther(ethAmount) without guarding for exceptions. parseEther throws on invalid/over-precise inputs (e.g. too many decimal places), which would crash the modal because this happens outside the try/catch in handleSubmit. Wrap the parseEther conversion in try/catch inside validate() and return a friendly input error when parsing fails.

Copilot uses AI. Check for mistakes.
Comment on lines +47 to +55
// wagmi v1 API
const { writeAsync, isLoading: isPending } = useContractWrite({
address: strategyAddress,
abi: TOP_DAWG_PARTNER_ABI,
functionName: "createMarkee",
chainId: base.id,
});

const publicClient = usePublicClient({ chainId: base.id });
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The app largely standardizes contract writes through useContractWriteWithConfirmations (adds chain-aware confirmations, simulation/toasts, and consistent error handling). Using raw useContractWrite + manual waitForTransactionReceipt here bypasses those behaviors and creates an inconsistent UX. Consider migrating this modal to useContractWriteWithConfirmations for consistency with the rest of the codebase (see apps/web/hooks/useContractWriteWithConfirmations.ts).

Copilot uses AI. Check for mistakes.
Comment on lines +105 to +110
} catch (err: any) {
setIsConfirming(false);
if (!err?.message?.includes("User rejected")) {
setInputError("Transaction failed. Please try again.");
}
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error handling checks err.message.includes("User rejected"), which is brittle and may miss other wallet/provider messages. The codebase already handles this robustly via error.cause instanceof UserRejectedRequestError (see apps/web/utils/transactionMessages.ts). Consider switching to that approach (or relying on useContractWriteWithConfirmations notifications) so user-rejection is detected consistently.

Copilot uses AI. Check for mistakes.
Comment on lines 21 to 22
import MarkeeSign from "@/components/MarkeeSign";
import { LightCommunity } from "@/components/Communities";
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import order likely violates the repo’s import/order + alphabetize rule: @/components/Communities should come before @/components/MarkeeSign within the internal group. Reorder these imports to keep lint passing.

Suggested change
import MarkeeSign from "@/components/MarkeeSign";
import { LightCommunity } from "@/components/Communities";
import { LightCommunity } from "@/components/Communities";
import MarkeeSign from "@/components/MarkeeSign";

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +10
const MARKEE_SUBGRAPH =
"https://gateway.thegraph.com/api/subgraphs/id/8kMCKUHSY7o6sQbsvufeLVo8PifxrsnagjVTMGcs6KdF";
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MARKEE_SUBGRAPH is hard-coded to The Graph gateway without incorporating the configured gateway key pattern used elsewhere (see apps/web/configs/chains.tsx getGatewayKey). If the gateway requires an API key (or changes), this client-side fetch will fail in production. Consider building this URL from NEXT_PUBLIC_SUBGRAPH_KEY (or routing via a Next.js API route) so the endpoint is environment-configurable and consistent with the rest of the app.

Suggested change
const MARKEE_SUBGRAPH =
"https://gateway.thegraph.com/api/subgraphs/id/8kMCKUHSY7o6sQbsvufeLVo8PifxrsnagjVTMGcs6KdF";
const MARKEE_SUBGRAPH_ID = "8kMCKUHSY7o6sQbsvufeLVo8PifxrsnagjVTMGcs6KdF";
const SUBGRAPH_GATEWAY_KEY = process.env.NEXT_PUBLIC_SUBGRAPH_KEY;
const DEFAULT_MARKEE_SUBGRAPH = `https://gateway.thegraph.com/api/subgraphs/id/${MARKEE_SUBGRAPH_ID}`;
const MARKEE_SUBGRAPH = SUBGRAPH_GATEWAY_KEY
? `https://gateway.thegraph.com/api/${SUBGRAPH_GATEWAY_KEY}/subgraphs/id/${MARKEE_SUBGRAPH_ID}`
: DEFAULT_MARKEE_SUBGRAPH;

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +85
<button
onClick={() => setModalOpen(true)}
className="group relative mx-auto mt-6 cursor-pointer"
aria-label="Click to edit this Markee sign"
>
{/* Sign body */}
<div className="border border-neutral-content/30 rounded px-10 py-5 min-w-[280px] max-w-sm bg-neutral hover:border-primary-content/50 transition-colors duration-200">
<p className="font-mono text-neutral-content text-base group-hover:text-primary-content transition-colors duration-200 text-center leading-snug">
{data ? data.message : "loading..."}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sign button can open the modal while data is still null (or after a fetch failure), but MarkeeModal then receives minimumPrice=0 / currentTopDawg=0, which can allow entering an amount that will revert on-chain. Consider disabling the button (or the submit action) until the subgraph data has loaded successfully, and/or surfacing a loading/error state in the modal.

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +83
const minBeat =
currentTopDawg > BigInt(0) ? currentTopDawg + BigInt(1) : minimumPrice;
const minBeatEth = parseFloat(formatEther(minBeat));

const validate = () => {
if (!message.trim()) {
setInputError("Message cannot be empty.");
return false;
}
if (!ethAmount || isNaN(parseFloat(ethAmount)) || parseFloat(ethAmount) <= 0) {
setInputError("Enter a valid ETH amount.");
return false;
}
if (minBeat > BigInt(0) && parseEther(ethAmount) < minBeat) {
setInputError(
`You need at least ${minBeatEth.toFixed(4)} ETH to become top dawg.`,
);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minBeat is currentTopDawg + 1 wei, but the UI and error message display minBeatEth.toFixed(4). For typical values, adding 1 wei won’t change the 4-decimal display, so the message can say “at least 1.0000 ETH” while actually requiring slightly more. Consider rounding the displayed minimum up to the UI’s input granularity (or increasing display precision / adjusting the min increment) so the error message matches the real requirement.

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +109
try {
const { hash } = await writeAsync({
args: [message.trim(), name.trim()],
value: parseEther(ethAmount),
});

if (hash && publicClient) {
setIsConfirming(true);
await publicClient.waitForTransactionReceipt({ hash });
setIsConfirming(false);
setIsSuccess(true);
onSuccess();
}
} catch (err: any) {
setIsConfirming(false);
if (!err?.message?.includes("User rejected")) {
setInputError("Transaction failed. Please try again.");
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If publicClient is undefined, a successful writeAsync will return a hash but the code will skip waiting for confirmations and never call onSuccess, leaving the modal in a confusing state. Handle the publicClient-missing case explicitly (e.g., show an error) or switch to useWaitForTransaction / the existing useContractWriteWithConfirmations hook so success is tracked reliably.

Suggested change
try {
const { hash } = await writeAsync({
args: [message.trim(), name.trim()],
value: parseEther(ethAmount),
});
if (hash && publicClient) {
setIsConfirming(true);
await publicClient.waitForTransactionReceipt({ hash });
setIsConfirming(false);
setIsSuccess(true);
onSuccess();
}
} catch (err: any) {
setIsConfirming(false);
if (!err?.message?.includes("User rejected")) {
setInputError("Transaction failed. Please try again.");
}
if (!publicClient) {
setInputError("Unable to connect to the network. Please refresh the page and try again.");
return;
}
setIsConfirming(true);
try {
const { hash } = await writeAsync({
args: [message.trim(), name.trim()],
value: parseEther(ethAmount),
});
if (hash) {
await publicClient.waitForTransactionReceipt({ hash });
setIsSuccess(true);
onSuccess();
} else {
setInputError("Transaction hash was not returned. Please try again.");
}
} catch (err: any) {
if (!err?.message?.includes("User rejected")) {
setInputError("Transaction failed. Please try again.");
}
} finally {
setIsConfirming(false);

Copilot uses AI. Check for mistakes.
Comment on lines +231 to +237
{/* Success state */}
{isSuccess && (
<div className="mb-4 rounded border border-green-500/30 bg-green-500/10 px-3 py-2 text-sm text-green-400">
🎉 Your message is live on the Gardens sign!
</div>
)}

Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isSuccess/success banner state is effectively unreachable because onSuccess() immediately closes/unmounts the modal in the parent. Either remove the success UI state, or delay closing so the user can see confirmation feedback (or use the app’s transaction toast notifications).

Suggested change
{/* Success state */}
{isSuccess && (
<div className="mb-4 rounded border border-green-500/30 bg-green-500/10 px-3 py-2 text-sm text-green-400">
🎉 Your message is live on the Gardens sign!
</div>
)}

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +56
fetch(MARKEE_SUBGRAPH, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: QUERY }),
})
.then((r) => r.json())
.then((res) => {
const markee = res.data?.markees?.[0];
const strategy = res.data?.topDawgPartnerStrategy;
setData({
message: markee?.currentMessage ?? "this is a sign.",
totalFundsAdded: BigInt(markee?.totalFundsAdded ?? 0),
minimumPrice: BigInt(strategy?.minimumPrice ?? 0),
markeeId: markee?.id ?? null,
});
})
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither fetch path checks response.ok nor handles GraphQL errors in the JSON payload. This can lead to setData being populated with defaults even when the query failed or returned errors. Please check r.ok and/or res.errors and treat those as errors (showing a fallback state) rather than silently continuing.

Copilot uses AI. Check for mistakes.
@Corantin Corantin merged commit a9c16d5 into mobile-view Feb 25, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants