Skip to content

Conversation

@KanishkSogani
Copy link
Member

@KanishkSogani KanishkSogani commented Sep 9, 2025

Summary by CodeRabbit

  • New Features

    • Live on-chain totals for profiles and testimonials with animated counters and a hook to fetch/format stats.
    • Improved sharing messages for testimonial requests and showcases; CTAs updated for smoother navigation.
  • Style

    • Major landing revamp: animated hero, refreshed features, How It Works, and testimonials sections with new gradients, icons, transitions, badges, and stat panels.
    • Navbar now adapts on scroll with a translucent blurred background.
  • Chores

    • Dependency update: framer-motion.
    • Updated deployment records and contract addresses.
    • README: added partner badges and top-section updates.

@coderabbitai
Copy link

coderabbitai bot commented Sep 9, 2025

Walkthrough

Adds on-chain counters and getters to VouchMe, updates ABI/TypeChain and factory, deploys a new contract address on chain 534351, and integrates on-chain stats into the web UI with a new hook and CountUp component; several landing page components, Navbar behavior, and a dependency were also updated.

Changes

Cohort / File(s) Summary
Deployment artifacts
contracts/broadcast/DeployVouchMe.s.sol/534351/run-1757402841.json, contracts/broadcast/DeployVouchMe.s.sol/534351/run-latest.json, contracts/broadcast/DeployVouchMe.s.sol/61/run-1759575443.json, contracts/broadcast/DeployVouchMe.s.sol/61/run-latest.json
Added and updated deployment records for chains 534351 and 61: new CREATE txs/receipts, contract addresses, gas/nonce/fee metrics, block hashes/numbers, timestamps, and commit metadata.
Solidity: counters and update logic
contracts/src/VouchMe.sol
Added uint256 public totalProfiles and totalTestimonials; modified setProfile and createTestimonial to increment counters only for new creations (updates do not increment); added external getters.
TypeChain typings
web/src/typechain-types/VouchMe.ts
Added typed entries and overloads for getTotalProfiles, getTotalTestimonials, and the totalProfiles/totalTestimonials wrappers to the VouchMe interface and getFunction unions.
Factory and ABI
web/src/typechain-types/factories/VouchMe__factory.ts
Expanded ABI with four view functions; updated bytecode; broadened VouchMeConstructorParams to accept full ContractFactory constructor signatures.
Contract address map
web/src/utils/contract.ts
Updated CONTRACT_ADDRESSES: Scroll Sepolia (534351) to 0x344fe9f4bee36dadd4b584be8e9a968b1515d291; updated chain 61 address.
Stats hook and animated counts
web/src/hooks/useContractStats.ts, web/src/components/ui/count-up.tsx
New client hook useContractStats reads on-chain totals (with minimum thresholds) and returns profiles/testimonials; new CountUp component animates numeric counts on viewport entry.
Landing page components
web/src/components/LandingPage/FeaturesSection.tsx, web/src/components/LandingPage/HeroSection.tsx, web/src/components/LandingPage/HowItWorks.tsx, web/src/components/LandingPage/TestimonialSection.tsx
Major visual/content revamp: gradients, decorative overlays, icon swaps, animated/staggered reveals, updated copy and CTAs, and Testimonial section switched to dynamic stats.
Navbar scroll behavior
web/src/components/Navbar.tsx
Added isScrolled state and a scroll listener to apply dynamic translucent/blurred background on the landing page.
Dashboard share messages
web/src/app/dashboard/page.tsx
Centralized share message strings into constants and replaced inline literals in share handlers.
New typechain factory and bytecode
web/src/typechain-types/factories/VouchMe__factory.ts
Bytecode and ABI updated to match Solidity changes; factory constructor typing broadened.
Dependency bump
web/package.json
Bumped framer-motion from ^12.4.7 to ^12.23.12.
Docs / README
README.md
Added badge/logo header and minor formatting fixes to local setup commands.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Contract as VouchMe
  Note right of Contract:#88CCEE fill:#f6fffe,stroke:#88CCEE
  Note right of Contract:New counters and update-aware logic

  User->>Contract: setProfile(name, metadata)
  alt name previously empty
    Contract->>Contract: totalProfiles++
  else
    Contract->>Contract: update profile fields
  end

  User->>Contract: createTestimonial(sender, receiver, content)
  alt existing testimonial from sender->receiver
    Contract->>Contract: remove old token / update
    Note right of Contract: totalTestimonials unchanged
  else
    Contract->>Contract: mint token
    Contract->>Contract: totalTestimonials++
  end

  User->>Contract: getTotalProfiles()
  Contract-->>User: uint256
  User->>Contract: getTotalTestimonials()
  Contract-->>User: uint256
Loading
sequenceDiagram
  autonumber
  participant UI as React UI
  participant Hook as useContractStats
  participant Wagmi as wagmi readContract
  participant Contract as VouchMe

  UI->>Hook: mount
  Hook->>Wagmi: read getTotalProfiles(contractAddress)
  Wagmi->>Contract: eth_call getTotalProfiles
  Contract-->>Wagmi: bigint
  Wagmi-->>Hook: bigint

  Hook->>Wagmi: read getTotalTestimonials(contractAddress)
  Wagmi->>Contract: eth_call getTotalTestimonials
  Contract-->>Wagmi: bigint
  Wagmi-->>Hook: bigint

  Hook->>Hook: apply min thresholds & toNumber
  Hook-->>UI: { profiles, testimonials }
  UI->>UI: <CountUp value=profiles /> and <CountUp value=testimonials />
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested reviewers

  • ceilican
  • Zahnentferner

Poem

hoppity-hop, I ship with glee,
counters on-chain for all to see,
counts grow true, edits stay neat,
UI gleams with gradients sweet.
I thump my foot — deploy we be! 🐰✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly summarizes the primary scope of the changeset by indicating both the landing page overhaul and the addition of total users and testimonials counters. It directly reflects the major UI updates across the landing page components and the new data-driven count functionality. This phrasing is clear, concise, and gives reviewers immediate insight into the pull request’s focus.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
contracts/src/VouchMe.sol (4)

214-221: Non-transferable override blocks burns — prevents deletion/update cleanup.

Overriding _update to require owner be zero forbids both transfers and burns. This makes tokens impossible to burn, leaving “ghost” tokens on updates/deletes.

Apply:

- function _update(address to, uint256 tokenId, address auth) internal override returns (address) {
-     require(_ownerOf(tokenId) == address(0), "Tokens are non-transferrable");
-     return super._update(to, tokenId, auth);
- }
+ function _update(address to, uint256 tokenId, address auth) internal override returns (address) {
+     address from = _ownerOf(tokenId);
+     // allow mint (from == 0) and burn (to == 0); disallow transfers
+     require(from == address(0) || to == address(0), "Tokens are non-transferrable");
+     return super._update(to, tokenId, auth);
+ }

89-97: On update, burn the old token and clear storage to avoid leaks.

Replacing a testimonial only removes mappings/arrays; the old NFT remains minted and locked forever.

Apply:

 uint256 existingTokenId = _testimonial[senderAddress][msg.sender];
 bool isUpdate = false;
 if (existingTokenId != 0) {
   isUpdate = true;
-  // Remove the existing testimonial
+  // Remove the existing testimonial
   _removeTestimonialFromList(existingTokenId, senderAddress, msg.sender);
+  // Burn old NFT and clear details
+  _burn(existingTokenId);
+  delete _testimonials[existingTokenId];
 }
 ...
 // Increment testimonials counter only for new testimonials (not updates)
 if (!isUpdate) {
   totalTestimonials++;
 }

Also applies to: 122-126


300-314: Delete should burn token and clear details.

Currently only mappings/arrays are updated, leaving a minted, unusable token.

Apply:

 function deleteTestimonial(uint256 tokenId) external {
   require(_ownerOf(tokenId) == msg.sender, "Only recipient can delete");
   // Check if the testimonial still exists
   address sender = _testimonials[tokenId].sender;
   require(_testimonial[sender][msg.sender] == tokenId, "Testimonial already deleted");
   _removeTestimonialFromList(tokenId, sender, msg.sender);
+  _burn(tokenId);
+  delete _testimonials[tokenId];
   emit TestimonialDeleted(tokenId, msg.sender);
 }

73-87: Prevent hash collisions and replay by using abi.encode with domain separation
Replace the abi.encodePacked block in contracts/src/VouchMe.sol (lines 73–87) with:

- bytes32 messageHash = keccak256(
-   abi.encodePacked(
-     senderAddress,
-     msg.sender,
-     content,
-     giverName,
-     profileUrl
-   )
- );
+ bytes32 messageHash = keccak256(
+   abi.encode(
+     senderAddress,
+     msg.sender,
+     content,
+     giverName,
+     profileUrl,
+     address(this),
+     block.chainid
+   )
+ );

Ensure any clients that produce signatures are updated to match this new encoding.

♻️ Duplicate comments (1)
web/src/typechain-types/VouchMe.ts (1)

588-591: Typed methods for total — mirrors getters.*

Same bigint handling applies as above; avoid duplicative RPCs by using one of getTotal* or total* consistently in hooks.

🧹 Nitpick comments (26)
web/src/components/Navbar.tsx (2)

27-36: Avoid initial flicker and reduce scroll overhead.

Initialize state on mount and use passive listener; also avoid redundant state updates.

Apply:

 useEffect(() => {
-  if (isLandingPage) {
-    const handleScroll = () => {
-      setIsScrolled(window.scrollY > 50);
-    };
-
-    window.addEventListener("scroll", handleScroll);
-    return () => window.removeEventListener("scroll", handleScroll);
-  }
+  if (!isLandingPage) return;
+  const handleScroll = () => {
+    const scrolled = window.scrollY > 50;
+    setIsScrolled((prev) => (prev !== scrolled ? scrolled : prev));
+  };
+  handleScroll(); // set initial
+  window.addEventListener("scroll", handleScroll, { passive: true });
+  return () => window.removeEventListener("scroll", handleScroll);
 }, [isLandingPage]);

47-57: Nav behavior is clear; consider consistency across routes (minor).

Landing uses fixed; others use static background. If unintended layout shift occurs between pages, consider fixed/sticky on all.

web/src/app/dashboard/page.tsx (1)

1285-1286: Ensure shared links include protocol; update X endpoint (optional).

Some shares use ${baseUrl} which strips https://, producing bare domains in posts. Use window.location.origin everywhere for share/copy. Optionally switch to https://x.com/intent/post.

Outside this diff, adjust base URL:

// lines ~255-259
useEffect(() => {
  if (typeof window !== "undefined") {
-   setBaseUrl(window.location.origin.replace(/^https?:\/\//, ""));
+   setBaseUrl(window.location.origin); // keep protocol
  }
}, []);

And keep consumers as ${baseUrl}/.... If you want visually trimmed display, keep truncateLink for UI only.

Also applies to: 1319-1320, 1336-1337, 1405-1406, 1441-1442, 1458-1459

contracts/src/VouchMe.sol (3)

14-16: Counter semantics: clarify “total” vs “active”.

totalProfiles/totalTestimonials only increment and never decrement. If UI intends “ever created”, this is fine; if “active”, decrement on delete.


175-190: Redundant getters.

Since totalProfiles/totalTestimonials are public, Solidity auto-generates getters. The explicit getters can be removed to save bytecode.


241-254: Profile “new” detection via name is brittle (minor).

Prefer a dedicated mapping(address => bool) hasProfile flag toggled on first set to decouple from field contents.

web/src/components/LandingPage/HeroSection.tsx (3)

13-13: Fix invalid Tailwind breakpoint prefix ("mb:pb-0").

"mb:" is not a valid breakpoint; looks like a typo for "md:". This class is currently a no-op.

-    <section className="relative min-h-screen flex items-center justify-center overflow-hidden pt-24 md:pt-16 mb:pb-0 pb-10">
+    <section className="relative min-h-screen flex items-center justify-center overflow-hidden pt-24 md:pt-16 md:pb-0 pb-10">

22-41: Mark decorative icons as aria-hidden and respect reduced motion.

Improves a11y by hiding purely decorative icons from screen readers and avoids motion for users preferring reduced motion.

-        <Shield
-          className="absolute top-20 left-10 w-6 h-6 text-yellow-400/20 animate-bounce"
+        <Shield
+          aria-hidden="true"
+          className="absolute top-20 left-10 w-6 h-6 text-yellow-400/20 motion-safe:animate-bounce"
           style={{ animationDelay: "0s" }}
         />
-        <Lock
-          className="absolute top-40 right-20 w-4 h-4 text-yellow-400/30 animate-bounce"
+        <Lock
+          aria-hidden="true"
+          className="absolute top-40 right-20 w-4 h-4 text-yellow-400/30 motion-safe:animate-bounce"
           style={{ animationDelay: "2s" }}
         />
-        <Users
-          className="absolute bottom-40 left-20 w-5 h-5 text-yellow-400/20 animate-bounce"
+        <Users
+          aria-hidden="true"
+          className="absolute bottom-40 left-20 w-5 h-5 text-yellow-400/20 motion-safe:animate-bounce"
           style={{ animationDelay: "4s" }}
         />
-        <Shield
-          className="absolute top-60 right-10 w-5 h-5 text-yellow-400/15 animate-bounce"
+        <Shield
+          aria-hidden="true"
+          className="absolute top-60 right-10 w-5 h-5 text-yellow-400/15 motion-safe:animate-bounce"
           style={{ animationDelay: "1s" }}
         />
-        <Lock
-          className="absolute bottom-20 right-40 w-4 h-4 text-yellow-400/25 animate-bounce"
+        <Lock
+          aria-hidden="true"
+          className="absolute bottom-20 right-40 w-4 h-4 text-yellow-400/25 motion-safe:animate-bounce"
           style={{ animationDelay: "3s" }}
         />
-            <Shield className="w-4 h-4 mr-2 text-yellow-400" />
+            <Shield aria-hidden="true" className="w-4 h-4 mr-2 text-yellow-400" />
-              <ArrowRight className="ml-2 w-5 h-5" />
+              <ArrowRight aria-hidden="true" className="ml-2 w-5 h-5" />

Also applies to: 48-49, 79-79


75-80: Prefer for navigation CTAs.

Semantically an anchor; Link enables prefetch and better accessibility. Keep button styles.

-            <button
-              onClick={() => router.push("/dashboard")}
-              className="w-full md:w-auto bg-indigo-600 hover:bg-indigo-700 text-white font-semibold px-5 py-3 rounded-lg transition-all duration-200 transform hover:scale-105 shadow-xl flex items-center justify-center"
-            >
+            <Link
+              href="/dashboard"
+              className="w-full md:w-auto bg-indigo-600 hover:bg-indigo-700 text-white font-semibold px-5 py-3 rounded-lg transition-all duration-200 transform hover:scale-105 shadow-xl flex items-center justify-center"
+            >
               Start Requesting Testimonials
               <ArrowRight aria-hidden="true" className="ml-2 w-5 h-5" />
-            </button>
+            </Link>
-            <button
-              onClick={() => router.push(showcasePath)}
+            <Link
+              href={showcasePath}
               className={`w-full md:w-auto border border-indigo-400/30 text-indigo-400 hover:bg-indigo-400/10 hover:border-indigo-400/50 px-5 py-3 rounded-lg transition-all duration-200 `}
-            >
+            >
               View Showcase
-            </button>
+            </Link>

Also applies to: 82-87

contracts/broadcast/DeployVouchMe.s.sol/534351/run-latest.json (1)

1-47: Consider excluding run-latest.json from VCS.

run-latest is mutable and often causes merge noise; the timestamped run file already pins the deployment. Consider .gitignoring run-latest.json.

web/src/components/LandingPage/HowItWorks.tsx (4)

88-91: Use a stable key instead of array index.

These steps are static; prefer step.number to avoid potential key issues on reordering.

-          {steps.map((step, index) => (
-            <div
-              key={index}
+          {steps.map((step, index) => (
+            <div
+              key={step.number}

110-114: Hide step icons from screen readers (decorative).

Headings already convey meaning; hide icons to reduce verbosity.

-                    <step.icon className="w-5 h-5 sm:w-6 sm:h-6 text-white" />
+                    <step.icon aria-hidden="true" className="w-5 h-5 sm:w-6 sm:h-6 text-white" />

132-137: Add aria-label to CTA for clarity.

Minor a11y polish.

-          <button
-            onClick={() => router.push("/dashboard")}
+          <button
+            aria-label="Start requesting testimonials"
+            onClick={() => router.push("/dashboard")}

66-70: Optional: Prefer for navigation targets.

Cards/CTAs navigate within the app; Link improves semantics and prefetch. Keep visual styles.

Also applies to: 81-87, 104-127, 131-137

web/src/typechain-types/factories/VouchMe__factory.ts (1)

476-501: Avoid duplicate surfaces for the same data

You now expose both getTotal* and total*; pick one for the frontend to avoid extra RPCs and confusion. If both remain for compat, document the preferred one and gate calls per network.

web/src/components/LandingPage/FeaturesSection.tsx (3)

37-38: Prevent any accidental pointer interception by decorative layers

Mark the background layers as non-interactive.

-      <div className="absolute inset-0 bg-[radial-gradient(circle_at_20%_50%,rgba(99,102,241,0.05),transparent_50%)]" />
-      <div className="absolute inset-0 bg-[radial-gradient(circle_at_80%_20%,rgba(20,184,166,0.03),transparent_50%)]" />
+      <div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_20%_50%,rgba(99,102,241,0.05),transparent_50%)]" />
+      <div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_80%_20%,rgba(20,184,166,0.03),transparent_50%)]" />

59-61: Stable keys and reduced-motion safety

Use a stable key and honor prefers-reduced-motion for long transitions.

-              key={index}
-              className="transition-all duration-1000"
+              key={feature.title}
+              className="transition-all duration-1000 motion-reduce:transition-none motion-reduce:transform-none"

68-68: Decorative icon should be hidden from assistive tech

Add aria-hidden to the icon.

-                    <feature.icon className="w-5 h-5 sm:w-6 sm:h-6 text-white" />
+                    <feature.icon aria-hidden="true" className="w-5 h-5 sm:w-6 sm:h-6 text-white" />
web/src/utils/contract.ts (2)

3-7: Tighten types and immutability of address map

Use satisfies + template literal type for checks, and freeze keys/values.

-export const CONTRACT_ADDRESSES: { [key: number]: string } = {
-  534351: "0x344fe9f4bee36dadd4b584be8e9a968b1515d291", // Scroll Sepolia
-  63: "0x3c9a98c58be8410c3510d5ccc671e35b7df55e08", // Mordor
-  61: "0x51a11e08643c9df6ceb5f7fb41a72334cfa7d1d6", // Ethereum Classic
-};
+export const CONTRACT_ADDRESSES = {
+  534351: "0x344fe9f4bee36dadd4b584be8e9a968b1515d291", // Scroll Sepolia
+  63: "0x3c9a98c58be8410c3510d5ccc671e35b7df55e08",   // Mordor
+  61: "0x51a11e08643c9df6ceb5f7fb41a72334cfa7d1d6",   // Ethereum Classic
+} as const satisfies Record<number, `0x${string}`>;

9-9: Avoid bundling factory bytecode into the client

Export only the ABI for read-only use to reduce bundle size; import the factory only in server/tooling.

-export const VouchMeFactory = VouchMe__factory;
+export const VouchMeAbi = VouchMe__factory.abi;

If needed elsewhere, provide a small helper outside client paths:

// web/src/server/contracts/vouchme.ts (server-only)
import { VouchMe__factory } from "@/typechain-types";
export const VouchMeFactory = VouchMe__factory;
web/src/hooks/useContractStats.ts (3)

9-12: Avoid UI flicker by aligning initial values with floors

Initial defaults (120/259) jump to 150/250 once effect runs. Start at the floored values to keep UI stable.

   const [stats, setStats] = useState({
-    profiles: 120,
-    testimonials: 259,
+    profiles: 150,
+    testimonials: 250,
   });
@@
-    setStats({
-      profiles: contractProfiles > 150 ? contractProfiles : 150,
-      testimonials: contractTestimonials > 250 ? contractTestimonials : 250,
-    });
+    setStats({
+      profiles: Math.max(contractProfiles, 150),
+      testimonials: Math.max(contractTestimonials, 250),
+    });

Also applies to: 35-38


29-34: Handle BigInt results safely from wagmi reads

useReadContract commonly returns bigint. Convert defensively to avoid NaN and make intent clear. If you expect these to remain under Number.MAX_SAFE_INTEGER, this is fine; otherwise, display as strings.

-    const contractProfiles = totalProfiles ? Number(totalProfiles) : 0;
-    const contractTestimonials = totalTestimonials
-      ? Number(totalTestimonials)
-      : 0;
+    const toNum = (v: unknown) =>
+      typeof v === "bigint" ? Number(v) : Number(v ?? 0);
+    const contractProfiles = toNum(totalProfiles);
+    const contractTestimonials = toNum(totalTestimonials);

17-27: Reduce RPC round-trips with a batched read

Optional: switch to useReadContracts to fetch both totals in one request and set a staleTime to limit refetches.

web/src/components/LandingPage/TestimonialSection.tsx (2)

53-56: Re-animate stats when values change (optional)

If you want the counters to re-animate on updated values, key the component by the value to force a remount.

-                  <CountUp value={profiles} delay={500} />+
+                  <CountUp key={profiles} value={profiles} delay={500} />+
@@
-                  <CountUp value={testimonials} delay={500} />+
+                  <CountUp key={testimonials} value={testimonials} delay={500} />+

Also applies to: 65-67


116-121: Prefer Link for client-side navigation and prefetch

Using Next.js <Link> improves a11y and enables prefetch. Optional—current approach works.

-                  <button
-                    onClick={() => router.push("/dashboard")}
-                    className="w-full bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-600 hover:to-purple-700 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-200 transform hover:scale-[1.02] shadow-lg"
-                  >
-                    Request Testimonial
-                  </button>
+                  <a
+                    href="/dashboard"
+                    className="w-full inline-flex justify-center bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-600 hover:to-purple-700 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-200 transform hover:scale-[1.02] shadow-lg"
+                  >
+                    Request Testimonial
+                  </a>

If you already use next/link, swap <a> with <Link href="/dashboard">...</Link>.

web/src/typechain-types/VouchMe.ts (1)

529-532: Typed methods for getTotal — confirm bigint handling in UI.*

TypeChain will return bigint at call sites (DefaultReturnType unwrap). Ensure UI converts safely (e.g., Number() with bounds or format from BigInt) before passing to CountUp/formatters to avoid SSR/serialization issues.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a824da and f3b124e.

⛔ Files ignored due to path filters (1)
  • web/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (15)
  • contracts/broadcast/DeployVouchMe.s.sol/534351/run-1757402841.json (1 hunks)
  • contracts/broadcast/DeployVouchMe.s.sol/534351/run-latest.json (2 hunks)
  • contracts/src/VouchMe.sol (5 hunks)
  • web/package.json (1 hunks)
  • web/src/app/dashboard/page.tsx (7 hunks)
  • web/src/components/LandingPage/FeaturesSection.tsx (1 hunks)
  • web/src/components/LandingPage/HeroSection.tsx (1 hunks)
  • web/src/components/LandingPage/HowItWorks.tsx (4 hunks)
  • web/src/components/LandingPage/TestimonialSection.tsx (1 hunks)
  • web/src/components/Navbar.tsx (3 hunks)
  • web/src/components/ui/count-up.tsx (1 hunks)
  • web/src/hooks/useContractStats.ts (1 hunks)
  • web/src/typechain-types/VouchMe.ts (10 hunks)
  • web/src/typechain-types/factories/VouchMe__factory.ts (3 hunks)
  • web/src/utils/contract.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
web/src/hooks/useContractStats.ts (1)
web/src/utils/contract.ts (1)
  • CONTRACT_ADDRESSES (3-7)
web/src/components/LandingPage/TestimonialSection.tsx (2)
web/src/hooks/useContractStats.ts (1)
  • useContractStats (8-42)
web/src/components/ui/count-up.tsx (1)
  • CountUp (14-59)
web/src/components/LandingPage/HeroSection.tsx (1)
web/src/components/ui/hero-highlight.tsx (1)
  • Highlight (6-39)
web/src/components/LandingPage/HowItWorks.tsx (1)
web/src/components/ui/card.tsx (2)
  • Card (80-80)
  • CardContent (85-85)
web/src/typechain-types/VouchMe.ts (1)
web/src/typechain-types/common.ts (1)
  • TypedContractMethod (107-131)
🔇 Additional comments (14)
web/src/components/Navbar.tsx (1)

20-20: State addition LGTM.

isScrolled is the right shape for a threshold toggle.

web/src/app/dashboard/page.tsx (1)

85-90: Good extraction of share-copy strings.

Centralizing these reduces duplication.

contracts/broadcast/DeployVouchMe.s.sol/534351/run-1757402841.json (1)

7-8: Address alignment verified
Contract address 0x344fe9f4bee36dadd4b584be8e9a968b1515d291 for chain 534351 matches the mapping in web/src/utils/contract.ts and the broadcast JSON; no conflicting .env or deploy config entries found.

contracts/broadcast/DeployVouchMe.s.sol/534351/run-latest.json (1)

4-15: Verify contract address, ABI/types alignment, and remove stale refs

  • Frontend should map chain 534351 to new address 0x344fe9f4bee36dadd4b584be8e9a968b1515d291
  • Ensure TypeChain/ABI in web/src/typechain-types and JSON ABIs include the new getters (getTotalProfiles, getTotalTestimonials, etc.)
  • Search the repo for any old address (0x270fa4703280ee537574358deeaf62238cad24b7) and remove or update stale references
web/src/typechain-types/factories/VouchMe__factory.ts (1)

222-247: App exclusively calls getTotalProfiles/getTotalTestimonials; undefined results fallback to 0 for older deployments

web/src/components/LandingPage/FeaturesSection.tsx (1)

32-36: Landing section refresh — LGTM

Section structure, theming, and layout changes look clean and consistent with the updated design system.

web/src/utils/contract.ts (1)

4-4: Resolved: Contract address and ABI getters confirmed
getCode returns bytecode (0x6080806040526004) at 0x344fe9f4bee36dadd4b584be8e9a968b1515d291 on Scroll Sepolia (chain 534351), and typechain definitions expose both getTotalProfiles and getTotalTestimonials getters.

web/src/typechain-types/VouchMe.ts (7)

132-139: encodeFunctionData overloads for getTotal — OK.*

No inputs expected; signatures align with view functions returning uint256.


178-185: encodeFunctionData overloads for total — OK.*

Matches public variable getters with no args.


221-228: decodeFunctionResult for getTotal — OK.*

Decoders added and aligned with encoders.


258-265: decodeFunctionResult for total — OK.*

Consistent with ABI expectations.


650-656: getFunction overloads for getTotal — OK.*

Overloads resolve correctly; no name collisions.


718-724: getFunction overloads for total — OK.*

Consistent with other overloads.


67-82: Approve selector additions
Verified that getTotalProfiles, getTotalTestimonials, totalProfiles, and totalTestimonials are present in VouchMe__factory.ts and used in useContractStats.ts.

"clsx": "^2.1.1",
"ethers": "^6.13.5",
"framer-motion": "^12.4.7",
"framer-motion": "^12.23.12",
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Framer Motion upgrade: verify peer-compat and duplication with motion.

With React 19/Next 15, confirm framer-motion@^12.23.12 plays nicely and whether both framer-motion and motion are needed. If only one is used, drop the other to avoid bloat.

Run:


🏁 Script executed:

#!/bin/bash
# Check imports
rg -nP --glob 'web/src/**' -C2 'from\s+[\'"]framer-motion|from\s+[\'"]motion'

# Quick peer check (local)
node -e 'const p=require("./web/package.json");console.log({react:p.dependencies.react,next:p.dependencies.next,framer:p.dependencies["framer-motion"],motion:p.dependencies.motion})'

Length of output: 269


🏁 Script executed:

#!/usr/bin/env bash
# Search for imports of framer-motion and motion in the web/src tree
rg -nP --glob 'web/src/**/*.{js,jsx,ts,tsx}' -n -C2 "from\s+['\"](framer-motion|motion)['\"]"

# List local versions of React, Next, framer-motion, and motion (if present)
echo "Local dependencies:"
jq -r '.dependencies | to_entries[] | "\(.key): \(.value)"' web/package.json

# Show peerDependencies for [email protected]
echo "[email protected] peerDependencies:"
npm view [email protected] peerDependencies --json

Length of output: 1299


Remove unused motion dependency
All components import from framer-motion, never the standalone motion package, and [email protected]’s peerDependencies (react@^18||^19, react-dom@^18||^19) are already satisfied. Drop "motion": "^12.4.7" from web/package.json.

🤖 Prompt for AI Agents
In web/package.json at line 24, remove the unused "motion": "^12.4.7" dependency
from the dependencies list; update the package.json by deleting that entry and
then run a package manager cleanup (npm/yarn pnpm install or npm prune) and
lockfile update to ensure the dependency is removed from node_modules and the
lockfile.

Comment on lines 10 to 11
const { address } = useAccount();

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Guard undefined wallet address in Showcase navigation.

When disconnected, address is undefined and the route becomes /testimonials?address=undefined. Provide a sane fallback.

   const { address } = useAccount();
+  const showcasePath = address ? `/testimonials?address=${address}` : "/testimonials";
-            <button
-              onClick={() => router.push(`/testimonials?address=${address}`)}
+            <button
+              onClick={() => router.push(showcasePath)}

Also applies to: 82-84

🤖 Prompt for AI Agents
In web/src/components/LandingPage/HeroSection.tsx around lines 10-11 (and also
apply same change at lines 82-84), the wallet address from useAccount() can be
undefined which results in routes like /testimonials?address=undefined; update
the navigation to guard the address by either using a sane fallback (e.g., empty
string) or, better, conditionally include the ?address=... query only when
address is truthy. Ensure you build the URL without the query param when address
is undefined or null so navigation becomes /testimonials (or
/testimonials?address=<shortenedAddress>) instead of containing "undefined".

Comment on lines 20 to 21
onClick={() => router.push("/dashboard")}
>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix nested interactive regions; add keyboard support.

Step 1 card is clickable and its inner code block is also clickable; this is redundant and can confuse users. Also add role/tabIndex + keydown handler for keyboard activation.

-        <div
-          className="mt-4 bg-gray-800/50 border border-gray-700/50 rounded-lg p-3 cursor-pointer hover:bg-gray-800/70 transition-colors"
-          onClick={() => router.push("/dashboard")}
-        >
+        <div
+          className="mt-4 bg-gray-800/50 border border-gray-700/50 rounded-lg p-3 hover:bg-gray-800/70 transition-colors"
+        >
-            <div
+            <div
               key={index}
-              className="relative transition-all duration-1000"
-              style={{
-                transitionDelay: `${index * 150}ms`,
-                cursor: index === 0 ? "pointer" : "default",
-              }}
-              onClick={
-                index === 0 ? () => router.push("/dashboard") : undefined
-              }
+              className={`relative transition-all duration-1000 ${index === 0 ? "cursor-pointer" : ""}`}
+              style={{ transitionDelay: `${index * 150}ms` }}
+              onClick={index === 0 ? () => router.push("/dashboard") : undefined}
+              role={index === 0 ? "button" : undefined}
+              tabIndex={index === 0 ? 0 : undefined}
+              onKeyDown={
+                index === 0
+                  ? (e) => {
+                      if (e.key === "Enter" || e.key === " ") router.push("/dashboard");
+                    }
+                  : undefined
+              }
             >

Also applies to: 91-98

🤖 Prompt for AI Agents
In web/src/components/LandingPage/HowItWorks.tsx around lines 20-21 and 91-98,
the Step card has nested clickable regions and lacks keyboard support; remove
the clickable behavior from the inner code block (or replace its onClick with a
non-interactive element / stopPropagation) so only the outer card handles
activation, then add accessible keyboard support and semantics to the outer card
by giving it role="button", tabIndex={0}, and an onKeyDown handler that triggers
the same navigation on Enter and Space; ensure the inner code block has no
role="button" or onClick so it is non-interactive and update tests/types if
needed.

Comment on lines +25 to +53
useEffect(() => {
if (isInView && !hasStarted) {
const timer = setTimeout(() => {
setHasStarted(true);

const startTime = Date.now();
const endTime = startTime + duration;

const updateCount = () => {
const now = Date.now();
const progress = Math.min((now - startTime) / duration, 1);

const currentCount = Math.floor(progress * value);
setCount(currentCount);

if (now < endTime) {
requestAnimationFrame(updateCount);
} else {
setCount(value);
}
};

updateCount();
}, delay);

return () => clearTimeout(timer);
}
}, [isInView, hasStarted, value, duration, delay]);

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Cancel requestAnimationFrame and timer on unmount to prevent leaks and React warnings

requestAnimationFrame isn’t canceled; unmounts can trigger setState on an unmounted component. Track and cancel the RAF in cleanup.

   useEffect(() => {
     if (isInView && !hasStarted) {
       const timer = setTimeout(() => {
         setHasStarted(true);

         const startTime = Date.now();
         const endTime = startTime + duration;

         const updateCount = () => {
           const now = Date.now();
           const progress = Math.min((now - startTime) / duration, 1);

           const currentCount = Math.floor(progress * value);
           setCount(currentCount);

           if (now < endTime) {
-            requestAnimationFrame(updateCount);
+            rafId.current = requestAnimationFrame(updateCount);
           } else {
             setCount(value);
           }
         };

         updateCount();
       }, delay);

-      return () => clearTimeout(timer);
+      return () => {
+        clearTimeout(timer);
+        if (rafId.current != null) {
+          cancelAnimationFrame(rafId.current);
+          rafId.current = null;
+        }
+      };
     }
   }, [isInView, hasStarted, value, duration, delay]);

Additionally, add the ref declaration:

   const ref = useRef(null);
   const isInView = useInView(ref, { once: true });
+  const rafId = useRef<number | null>(null);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
if (isInView && !hasStarted) {
const timer = setTimeout(() => {
setHasStarted(true);
const startTime = Date.now();
const endTime = startTime + duration;
const updateCount = () => {
const now = Date.now();
const progress = Math.min((now - startTime) / duration, 1);
const currentCount = Math.floor(progress * value);
setCount(currentCount);
if (now < endTime) {
requestAnimationFrame(updateCount);
} else {
setCount(value);
}
};
updateCount();
}, delay);
return () => clearTimeout(timer);
}
}, [isInView, hasStarted, value, duration, delay]);
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
const rafId = useRef<number | null>(null);
useEffect(() => {
if (isInView && !hasStarted) {
const timer = setTimeout(() => {
setHasStarted(true);
const startTime = Date.now();
const endTime = startTime + duration;
const updateCount = () => {
const now = Date.now();
const progress = Math.min((now - startTime) / duration, 1);
const currentCount = Math.floor(progress * value);
setCount(currentCount);
if (now < endTime) {
rafId.current = requestAnimationFrame(updateCount);
} else {
setCount(value);
}
};
updateCount();
}, delay);
return () => {
clearTimeout(timer);
if (rafId.current != null) {
cancelAnimationFrame(rafId.current);
rafId.current = null;
}
};
}
}, [isInView, hasStarted, value, duration, delay]);
🤖 Prompt for AI Agents
In web/src/components/ui/count-up.tsx around lines 25 to 53, the effect starts a
setTimeout and uses requestAnimationFrame but does not cancel the RAF or ensure
the timeout/RAF stop on unmount, and the reviewer also requested adding the
missing ref declaration; update the effect to store the timeout id and the raf
id in refs (e.g., timeoutRef and rafRef), cancel the timeout and call
cancelAnimationFrame for the stored raf id in the cleanup, ensure any
in-progress updateCount checks the mounted state or existence of rafRef before
calling setCount, and add the requested ref declaration for these refs at the
top of the component so both timer and RAF are cleared to prevent state updates
after unmount.

Comment on lines +53 to +56

return (
<span ref={ref} className={className}>
{count.toLocaleString()}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Update count when value changes after the initial animation

If value changes later (e.g., after RPC resolves), the component doesn’t reflect it. Set the final value when already started and in view.

-  return (
+  useEffect(() => {
+    if (hasStarted && isInView) setCount(value);
+  }, [value, hasStarted, isInView]);
+
+  return (
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (
<span ref={ref} className={className}>
{count.toLocaleString()}
useEffect(() => {
if (hasStarted && isInView) setCount(value);
}, [value, hasStarted, isInView]);
return (
<span ref={ref} className={className}>
{count.toLocaleString()}
🤖 Prompt for AI Agents
In web/src/components/ui/count-up.tsx around lines 53 to 56, the component only
animates on first mount and doesn’t update when the value prop changes later; to
fix, add an effect that watches value (and the in-view/started flags) and if the
animation has already started and the element is in view, set the final
displayed count to the new value (or restart the animation) by updating the
internal state/ref that drives the count; ensure this effect uses the same
formatting and uses toLocaleString when updating the displayed count so
RPC-delivered updates are reflected immediately.

Comment on lines +15 to +27
const contractAddress = CONTRACT_ADDRESSES[chainId];

const { data: totalProfiles } = useReadContract({
address: contractAddress as `0x${string}`,
abi: VouchMeABI.abi,
functionName: "getTotalProfiles",
});

const { data: totalTestimonials } = useReadContract({
address: contractAddress as `0x${string}`,
abi: VouchMeABI.abi,
functionName: "getTotalTestimonials",
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Guard against undefined contract address and bind to the active chain to prevent runtime errors

CONTRACT_ADDRESSES[chainId] can be undefined; casting it to 0x${string} and calling the contract will error. Also, explicitly binding chainId and gating the query avoids accidental calls on the wrong network.

Apply this diff:

   const chainId = useChainId();
   const contractAddress = CONTRACT_ADDRESSES[chainId];
+  const enabled = Boolean(contractAddress);

   const { data: totalProfiles } = useReadContract({
-    address: contractAddress as `0x${string}`,
+    address: contractAddress as `0x${string}`,
     abi: VouchMeABI.abi,
     functionName: "getTotalProfiles",
+    chainId,
+    query: { enabled },
   });

   const { data: totalTestimonials } = useReadContract({
-    address: contractAddress as `0x${string}`,
+    address: contractAddress as `0x${string}`,
     abi: VouchMeABI.abi,
     functionName: "getTotalTestimonials",
+    chainId,
+    query: { enabled },
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const contractAddress = CONTRACT_ADDRESSES[chainId];
const { data: totalProfiles } = useReadContract({
address: contractAddress as `0x${string}`,
abi: VouchMeABI.abi,
functionName: "getTotalProfiles",
});
const { data: totalTestimonials } = useReadContract({
address: contractAddress as `0x${string}`,
abi: VouchMeABI.abi,
functionName: "getTotalTestimonials",
});
const chainId = useChainId();
const contractAddress = CONTRACT_ADDRESSES[chainId];
const enabled = Boolean(contractAddress);
const { data: totalProfiles } = useReadContract({
address: contractAddress as `0x${string}`,
abi: VouchMeABI.abi,
functionName: "getTotalProfiles",
chainId,
query: { enabled },
});
const { data: totalTestimonials } = useReadContract({
address: contractAddress as `0x${string}`,
abi: VouchMeABI.abi,
functionName: "getTotalTestimonials",
chainId,
query: { enabled },
});
🤖 Prompt for AI Agents
In web/src/hooks/useContractStats.ts around lines 15 to 27, guard against
CONTRACT_ADDRESSES[chainId] being undefined and bind reads to the active chain:
first resolve const contractAddress = CONTRACT_ADDRESSES[chainId]; then pass
that address only when defined (use a boolean enabled flag like enabled:
!!contractAddress) to both useReadContract calls, include the chainId option on
each useReadContract to bind the query to the active chain, and avoid casting an
undefined value to `0x${string}` so the hook never attempts to call the contract
if contractAddress is missing.

Comment on lines 910 to 912
const _bytecode =
"0x60806040523461033a57604080519081016001600160401b03811182821017610247576040908152601382527f566f7563684d652054657374696d6f6e69616c00000000000000000000000000602083015280519081016001600160401b038111828210176102475760405260058152640ac9eaa86960db1b602082015281516001600160401b03811161024757600054600181811c91168015610330575b602082101461022757601f81116102cc575b50602092601f8211600114610268579281929360009261025d575b50508160011b916000199060031b1c1916176000555b80516001600160401b03811161024757600154600181811c9116801561023d575b602082101461022757601f81116101c2575b50602091601f821160011461015e57918192600092610153575b50508160011b916000199060031b1c1916176001555b60405161271490816103408239f35b01519050388061012e565b601f198216926001600052806000209160005b8581106101aa57508360019510610191575b505050811b01600155610144565b015160001960f88460031b161c19169055388080610183565b91926020600181928685015181550194019201610171565b60016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061021d575b601f0160051c01905b8181106102115750610114565b60008155600101610204565b90915081906101fb565b634e487b7160e01b600052602260045260246000fd5b90607f1690610102565b634e487b7160e01b600052604160045260246000fd5b0151905038806100cb565b601f1982169360008052806000209160005b8681106102b4575083600195961061029b575b505050811b016000556100e1565b015160001960f88460031b161c1916905538808061028d565b9192602060018192868501518155019401920161027a565b600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c81019160208410610326575b601f0160051c01905b81811061031a57506100b0565b6000815560010161030d565b9091508190610304565b90607f169061009e565b600080fdfe608080604052600436101561001357600080fd5b60003560e01c9081626a9ad714611bd857508063010b113e14611b8157806301ffc9a714611af957806306fdde0314611a54578063081812fc14611a16578063095ea7b31461192757806323b872dd14611910578063332d56d71461188557806342842e0e1461185b57806343ec6bdd14610be2578063526403141461079c5780635f74900e146107625780636352211e1461073257806370a08231146106dc5780637f1e86ed146105ac57806395d89b41146104df578063a22cb46514610435578063b88d4fde146103d4578063bc40ebb81461019c578063c87b56dd146101655763e985e9c51461010557600080fd5b346101605760403660031901126101605761011e611c8f565b610126611ca5565b9060018060a01b0316600052600560205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b600080fd5b3461016057602036600319011261016057610198610184600435612206565b604051918291602083526020830190611cde565b0390f35b3461016057602036600319011261016057600435600060c06040516101c081611d77565b82815282602082015260606040820152606080820152606060808201528260a0820152015280600052600260205260018060a01b03604060002054161561038f576000818152600a6020908152604080832080546001909101546001600160a01b039182168552600b84528285209116845290915290205481900361034a57600052600a602052604060002060405161025881611d77565b81546001600160a01b039081168252600183015416602082019081529161028160028201611db3565b6040830190815261033761029760038401611db3565b606085019081526103246102ad60048601611db3565b916080870192835261031160ff600660058901549860a08b01998a520154169560c089019615158752604051998a9960208b5260018060a01b0390511660208b015260018060a01b0390511660408a01525160e060608a0152610100890190611cde565b9051878203601f19016080890152611cde565b9051858203601f190160a0870152611cde565b915160c084015251151560e08301520390f35b60405162461bcd60e51b815260206004820152601c60248201527f54657374696d6f6e69616c20686173206265656e2064656c65746564000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f54657374696d6f6e69616c20646f6573206e6f742065786973740000000000006044820152606490fd5b34610160576080366003190112610160576103ed611c8f565b6103f5611ca5565b606435916001600160401b038311610160573660238401121561016057610429610433933690602481600401359101611e9f565b91604435916120b8565b005b346101605760403660031901126101605761044e611c8f565b6024359081151590818303610160576001600160a01b03169182156104ca5761049c9033600052600560205260406000208460005260205260406000209060ff801983541691151516179055565b6040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b82630b61174360e31b60005260045260246000fd5b3461016057600036600319011261016057604051600060015461050181611d3d565b80845290600181169081156105885750600114610529575b6101988361018481850382611d92565b600160009081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6939250905b80821061056e57509091508101602001610184610519565b919260018160209254838588010152019101909291610556565b60ff191660208086019190915291151560051b840190910191506101849050610519565b34610160576020366003190112610160576004356000818152600260205260409020546001600160a01b03163303610697576000818152600a60209081526040808320546001600160a01b0316808452600b835281842033855290925290912054829003610652577faf1124c3e9482c81914cfd7af9eff6d985406bab38bdbb6fefc7bc3d8614773f91610644604092339083612270565b8151908152336020820152a1005b60405162461bcd60e51b815260206004820152601b60248201527f54657374696d6f6e69616c20616c72656164792064656c6574656400000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920726563697069656e742063616e2064656c657465000000000000006044820152606490fd5b34610160576020366003190112610160576001600160a01b036106fd611c8f565b16801561071c5760005260036020526020604060002054604051908152f35b6322718ad960e21b600052600060045260246000fd5b34610160576020366003190112610160576020610750600435612239565b6040516001600160a01b039091168152f35b34610160576020366003190112610160576001600160a01b03610783611c8f565b1660005260086020526020604060002054604051908152f35b34610160576060366003190112610160576004356001600160401b038111610160576107cc903690600401611e57565b6024356001600160401b038111610160576107eb903690600401611e57565b92906044356001600160401b0381116101605761080c903690600401611e57565b93909160405195606087018781106001600160401b03821117610a5857610857956108489461083f926040523691611e9f565b87523691611e9f565b92602085019384523691611e9f565b6040830190815233600052600c602052604060002092519283516001600160401b038111610a58576108898254611d3d565b601f8111610b9a575b50602094601f8211600114610b3557948192939495600092610b2a575b50508160011b916000199060031b1c19161781555b6001810192519283516001600160401b038111610a58576108e58254611d3d565b601f8111610ae2575b506020601f8211600114610a7957819060029596600092610a6e575b50508160011b916000199060031b1c19161790555b0190519081516001600160401b038111610a585761093d8254611d3d565b601f8111610a10575b50602092601f82116001146109ad57928192936000926109a2575b50508160011b916000199060031b1c19161790555b7fbe4ec58a792f909e102ee3d745d0c3b34a4d437a54d903c4db098d31c556422f6020604051338152a1005b015190508380610961565b601f1982169383600052806000209160005b8681106109f857508360019596106109df575b505050811b019055610976565b015160001960f88460031b161c191690558380806109d2565b919260206001819286850151815501940192016109bf565b826000526020600020601f830160051c81019160208410610a4e575b601f0160051c01905b818110610a425750610946565b60008155600101610a35565b9091508190610a2c565b634e487b7160e01b600052604160045260246000fd5b01519050868061090a565b601f1982169583600052816000209660005b818110610aca5750916002969791846001959410610ab1575b505050811b01905561091f565b015160001960f88460031b161c19169055868080610aa4565b83830151895560019098019760209384019301610a8b565b826000526020600020601f830160051c81019160208410610b20575b601f0160051c01905b818110610b1457506108ee565b60008155600101610b07565b9091508190610afe565b0151905085806108af565b601f1982169583600052806000209160005b888110610b8257508360019596979810610b69575b505050811b0181556108c4565b015160001960f88460031b161c19169055858080610b5c565b91926020600181928685015181550194019201610b47565b826000526020600020601f830160051c81019160208410610bd8575b601f0160051c01905b818110610bcc5750610892565b60008155600101610bbf565b9091508190610bb6565b346101605760a036600319011261016057610bfb611c8f565b6024356001600160401b03811161016057610c1a903690600401611e57565b6044356001600160401b03811161016057610c39903690600401611e57565b9290916064356001600160401b03811161016057610c5b903690600401611e57565b6084959195356001600160401b03811161016057610c7d903690600401611e57565b60405160608a811b6bffffffffffffffffffffffff1916602083019081523390911b60348301526001600160a01b038b169893899392909190888a604883013780878d818b8d8501818c6048830160008152370160480191600083528237016000815203601f1981018252610cf29082611d92565b5190207f19457468657265756d205369676e6564204d6573736167653a0a333200000000600052601c52603c600020913690610d2d92611e9f565b610d3691612349565b610d3f91612385565b6001600160a01b031603611822576000868152600b60209081526040808320338452909152902054801515989089611810575b505060075460001981146117fa57600101968760075533156117e4576000888152600260205260408120546001600160a01b031661179f57888152600260205260408120546001600160a01b0316801515918a908361176a575b33808252600360209081526040808420805460010190558484526002909152822080546001600160a01b031916821790559083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9080a45061175457610e61610e7092610e5260405198610e408a611d77565b8a8a5260208a0198338a523691611e9f565b95604089019687523691611e9f565b92606087019384523691611e9f565b608085019081524260a08601908152600160c0870181815260008a8152600a60205260409020975188546001600160a01b03199081166001600160a01b03928316178a55975192890180549098169216919091179095559251805191929160028701916001600160401b038211610a58578190610eed8454611d3d565b601f8111611701575b50602090601f831160011461169c57600092611691575b50508160011b916000199060031b1c19161790555b51805160038601916001600160401b038211610a58578190610f448454611d3d565b601f811161163e575b50602090601f83116001146115d9576000926115ce575b50508160011b916000199060031b1c19161790555b51805160048501916001600160401b038211610a5857610f998354611d3d565b601f8111611586575b50602090601f8311600114611516579180610ff7979694926006969460009261150b575b50508160011b916000199060031b1c19161790555b51600584015551151591019060ff801983541691151516179055565b3360009081526008602052604090208054908168010000000000000000811015610a585761102f81611048936001889401815561208a565b90919082549060031b91821b91600019901b1916179055565b82600052600960205260406000205580600052600b602052604060002060018060a01b0333166000526020528160406000205581600052600a60205260406000209260405161109681611d77565b84546001600160a01b03908116825260018601541660208201908152946110bf60028201611db3565b90604083019182526110d360038201611db3565b90606084019182526110e760048201611db3565b6080850190815260ff600660058401549360a088019485520154169260c08601931515845261114b61113e61112e61111e8c61240d565b98516001600160a01b031661257c565b9b516001600160a01b031661257c565b955191519251935161240d565b9351600090156114e45750604051611164604082611d92565b60048152637472756560e01b6020820152945b6040519a8b976b3d913a37b5b2b724b2111d1160a11b60208a015280519081602c8b0191602001916111a892611cbb565b88016b11161139b2b73232b9111d1160a11b602c820152815191826038830191602001916111d592611cbb565b01602c016d1116113932b1b2b4bb32b9111d1160911b600c82015281519182601a8301916020019161120692611cbb565b01600c016c11161131b7b73a32b73a111d1160991b600e82015281519182601b8301916020019161123692611cbb565b01600e016e11161133b4bb32b92730b6b2911d1160891b600d82015281519182601c8301916020019161126892611cbb565b01600d016f111611383937b334b632aab936111d1160811b600f82015281519182601f8301916020019161129b92611cbb565b01600f016e1116113a34b6b2b9ba30b6b8111d1160891b601082015281519182601f830191602001916112cd92611cbb565b016010016d1116113b32b934b334b2b2111d1160911b600f82015281519182601d830191602001916112fe92611cbb565b01600f0161227d60f01b600e82015203600e01601d19810185526002016113259085611d92565b826000526006602052604060002084516001600160401b038111610a585761134d8254611d3d565b601f811161149c575b50806020968790601f83116001146114385760009261142d575b50508160011b916000199060031b1c19161790555b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce784604051858152a17f9b09e829d78f88a15b1ae45769958983b0d2685486bbb34e98013c03fe17a18060606040518581528487820152336040820152a16113f1575b50604051908152f35b60607fc18cfb482b914e0d363259c5d2a3bfc28e241e5bc5ebc5485428e2adc1262c44916040519081523385820152836040820152a1826113e8565b015190508780611370565b60008581528281209350601f198516905b818110611485575090846001959493921061146c575b505050811b019055611385565b015160001960f88460031b161c1916905587808061145f565b92938a600181928786015181550195019301611449565b826000526020600020601f830160051c810191602084106114da575b601f0160051c01905b8181106114ce5750611356565b600081556001016114c1565b90915081906114b8565b506040516114f3604082611d92565b600581526466616c736560d81b602082015294611177565b015190508b80610fc6565b90601f1983169184600052816000209260005b81811061156e575092600192859260069896610ff79b9a989610611555575b505050811b019055610fdb565b015160001960f88460031b161c191690558b8080611548565b92936020600181928786015181550195019301611529565b836000526020600020601f840160051c810191602085106115c4575b601f0160051c01905b8181106115b85750610fa2565b600081556001016115ab565b90915081906115a2565b015190508a80610f64565b60008581528281209350601f198516905b818110611626575090846001959493921061160d575b505050811b019055610f79565b015160001960f88460031b161c191690558a8080611600565b929360206001819287860151815501950193016115ea565b909150836000526020600020601f840160051c81019160208510611687575b90601f859493920160051c01905b8181106116785750610f4d565b6000815584935060010161166b565b909150819061165d565b015190508b80610f0d565b60008581528281209350601f198516905b8181106116e957509084600195949392106116d0575b505050811b019055610f22565b015160001960f88460031b161c191690558b80806116c3565b929360206001819287860151815501950193016116ad565b909150836000526020600020601f840160051c8101916020851061174a575b90601f859493920160051c01905b81811061173b5750610ef6565b6000815584935060010161172e565b9091508190611720565b6339e3563760e11b600052600060045260246000fd5b600082815260046020526040902080546001600160a01b03191690558281526003602052604081208054600019019055610dcc565b60405162461bcd60e51b815260206004820152601c60248201527f546f6b656e7320617265206e6f6e2d7472616e736665727261626c65000000006044820152606490fd5b633250574960e11b600052600060045260246000fd5b634e487b7160e01b600052601160045260246000fd5b61181b913391612270565b8880610d72565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b346101605761043361186c36611d03565b906040519261187c602085611d92565b600084526120b8565b34610160576020366003190112610160576001600160a01b036118a6611c8f565b16600052600c6020526118f460406000206101986118c382611db3565b916119026118df60026118d860018501611db3565b9301611db3565b91604051958695606087526060870190611cde565b908582036020870152611cde565b908382036040850152611cde565b346101605761043361192136611d03565b91611ed6565b3461016057604036600319011261016057611940611c8f565b60243561194c81612239565b33151580611a03575b806119d5575b6119c05781906001600160a01b0384811691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4600090815260046020526040902080546001600160a01b0319166001600160a01b03909216919091179055005b63a9fbf51f60e01b6000523360045260246000fd5b506001600160a01b038116600090815260056020908152604080832033845290915290205460ff161561195b565b506001600160a01b038116331415611955565b3461016057602036600319011261016057600435611a3381612239565b506000526004602052602060018060a01b0360406000205416604051908152f35b346101605760003660031901126101605760405160008054611a7581611d3d565b80845290600181169081156105885750600114611a9c576101988361018481850382611d92565b60008080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563939250905b808210611adf57509091508101602001610184610519565b919260018160209254838588010152019101909291611ac7565b346101605760203660031901126101605760043563ffffffff60e01b811680910361016057602090632483248360e11b8114908115611b3e575b506040519015158152f35b6380ac58cd60e01b811491508115611b70575b8115611b5f575b5082611b33565b6301ffc9a760e01b14905082611b58565b635b5e139f60e01b81149150611b51565b3461016057604036600319011261016057611b9a611c8f565b611ba2611ca5565b6001600160a01b039182166000908152600b60209081526040808320939094168252918252829020548251811515815291820152f35b34610160576020366003190112610160576001600160a01b03611bf9611c8f565b16600052600860205260406000209081548082526020820190819360005260206000209060005b818110611c795750505081611c36910382611d92565b6040519182916020830190602084525180915260408301919060005b818110611c60575050500390f35b8251845285945060209384019390920191600101611c52565b8254845260209093019260019283019201611c20565b600435906001600160a01b038216820361016057565b602435906001600160a01b038216820361016057565b60005b838110611cce5750506000910152565b8181015183820152602001611cbe565b90602091611cf781518092818552858086019101611cbb565b601f01601f1916010190565b6060906003190112610160576004356001600160a01b038116810361016057906024356001600160a01b0381168103610160579060443590565b90600182811c92168015611d6d575b6020831014611d5757565b634e487b7160e01b600052602260045260246000fd5b91607f1691611d4c565b60e081019081106001600160401b03821117610a5857604052565b90601f801991011681019081106001600160401b03821117610a5857604052565b9060405191826000825492611dc784611d3d565b8084529360018116908115611e355750600114611dee575b50611dec92500383611d92565b565b90506000929192526020600020906000915b818310611e19575050906020611dec9282010138611ddf565b6020919350806001915483858901015201910190918492611e00565b905060209250611dec94915060ff191682840152151560051b82010138611ddf565b9181601f84011215610160578235916001600160401b038311610160576020838186019501011161016057565b6001600160401b038111610a5857601f01601f191660200190565b929192611eab82611e84565b91611eb96040519384611d92565b829481845281830111610160578281602093846000960137010152565b6001600160a01b03909116919082156117e4576000828152600260205260408120549093906001600160a01b031661179f57828452600260205260408420546001600160a01b031693839190859033151580611ff2575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9082611fbd575b83815260036020526040812060018154019055848152600260205260408120846bffffffffffffffffffffffff60a01b82541617905580a46001600160a01b0316808303611fa357505050565b6364283d7b60e01b60005260045260245260445260646000fd5b600085815260046020526040902080546001600160a01b03191690558281526003602052604081208054600019019055611f56565b91509192508061203b575b1561200c579084849238611f2d565b83908561202557602491637e27328960e01b8252600452fd5b60449163177e802f60e01b825233600452602452fd5b503385148015612069575b80611ffd5750838152600460205260408120546001600160a01b03163314611ffd565b5084815260056020908152604080832033845290915281205460ff16612046565b80548210156120a25760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b92916120c5818386611ed6565b813b6120d2575b50505050565b604051630a85bd0160e11b81523360048201526001600160a01b039485166024820152604481019190915260806064820152921691906020908290819061211d906084830190611cde565b03816000865af180916000916121bc575b509061218757503d15612180573d61214581611e84565b906121536040519283611d92565b81523d6000602083013e5b8051908161217b5782633250574960e11b60005260045260246000fd5b602001fd5b606061215e565b6001600160e01b03191663757a42ff60e11b016121a85750388080806120cc565b633250574960e11b60005260045260246000fd5b6020813d6020116121fe575b816121d560209383611d92565b810103126121fa5751906001600160e01b0319821682036121f757503861212e565b80fd5b5080fd5b3d91506121c8565b61220f81612239565b5060005260066020526122256040600020611db3565b6000604051612235602082611d92565b5290565b6000818152600260205260409020546001600160a01b031690811561225c575090565b637e27328960e01b60005260045260246000fd5b6001600160a01b039182166000908152600b602090815260408083209490951682529283528381208190556008835283812082825260099093529290922054815460001981019081116117fa57808203612315575b5050805480156122ff5760001901906122de828261208a565b8154906000199060031b1b1916905555600052600960205260006040812055565b634e487b7160e01b600052603160045260246000fd5b61231f908361208a565b90549060031b1c6123348161102f848661208a565b600052600960205260406000205538806122c5565b815191906041830361237a5761237392506020820151906060604084015193015160001a90612649565b9192909190565b505060009160029190565b91909160048110156123f7578061239b57509050565b6000600182036123b65763f645eedf60e01b60005260046000fd5b50600281036123d4578263fce698f760e01b60005260045260246000fd5b90916003600092146123e4575050565b6335e2f38360e21b825260045260249150fd5b634e487b7160e01b600052602160045260246000fd5b8060009172184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b821015612559575b806d04ee2d6d415b85acef8100000000600a92101561253e575b662386f26fc1000081101561252a575b6305f5e100811015612519575b61271081101561250a575b60648110156124fc575b10156124f1575b600a6021600184019361249585611e84565b946124a36040519687611d92565b8086526124b2601f1991611e84565b013660208701378401015b60001901916f181899199a1a9b1b9c1cb0b131b232b360811b8282061a83530480156124ec57600a90916124bd565b505090565b600190910190612483565b60646002910493019261247c565b61271060049104930192612472565b6305f5e10060089104930192612467565b662386f26fc100006010910493019261245a565b6d04ee2d6d415b85acef81000000006020910493019261244a565b506040915072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8104612430565b604051906001600160a01b031680612595606084611d92565b602a83526020830160403682378351156120a257603090538251600110156120a2576078602184015360295b600181116125eb57506125d2575090565b63e22e27eb60e01b600052600452601460245260446000fd5b90600f811660108110156120a2576000855184101561263557506f181899199a1a9b1b9c1cb0b131b232b360811b901a8483016020015360041c9080156117fa57600019016125c1565b634e487b7160e01b81526032600452602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116126d2579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156126c6576000516001600160a01b038116156126ba5790600090600090565b50600090600190600090565b6040513d6000823e3d90fd5b5050506000916003919056fea2646970667358221220fbd7d9e6490daa54cabed934df3f76331e83470ac06a047359e8a5bbbaafff5664736f6c634300081c0033";
"0x60806040523461033a57604080519081016001600160401b03811182821017610247576040908152601382527f566f7563684d652054657374696d6f6e69616c00000000000000000000000000602083015280519081016001600160401b038111828210176102475760405260058152640ac9eaa86960db1b602082015281516001600160401b03811161024757600054600181811c91168015610330575b602082101461022757601f81116102cc575b50602092601f8211600114610268579281929360009261025d575b50508160011b916000199060031b1c1916176000555b80516001600160401b03811161024757600154600181811c9116801561023d575b602082101461022757601f81116101c2575b50602091601f821160011461015e57918192600092610153575b50508160011b916000199060031b1c1916176001555b6040516127ff90816103408239f35b01519050388061012e565b601f198216926001600052806000209160005b8581106101aa57508360019510610191575b505050811b01600155610144565b015160001960f88460031b161c19169055388080610183565b91926020600181928685015181550194019201610171565b60016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061021d575b601f0160051c01905b8181106102115750610114565b60008155600101610204565b90915081906101fb565b634e487b7160e01b600052602260045260246000fd5b90607f1690610102565b634e487b7160e01b600052604160045260246000fd5b0151905038806100cb565b601f1982169360008052806000209160005b8681106102b4575083600195961061029b575b505050811b016000556100e1565b015160001960f88460031b161c1916905538808061028d565b9192602060018192868501518155019401920161027a565b600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c81019160208410610326575b601f0160051c01905b81811061031a57506100b0565b6000815560010161030d565b9091508190610304565b90607f169061009e565b600080fdfe608080604052600436101561001357600080fd5b60003560e01c9081626a9ad714611c9e57508063010b113e14611c4757806301ffc9a714611bbf57806306fdde0314611b1a578063081812fc14611adc578063095ea7b3146119ed57806323b872dd146119d657806324b32f9f146107e6578063332d56d71461194b57806342842e0e1461192157806343ec6bdd14610c8657806352640314146108045780635eb3740e146107e65780635f74900e146107ac5780636352211e1461077c57806370a08231146107265780637f1e86ed146105f657806395d89b4114610529578063a22cb4651461047f578063b88d4fde1461041e578063bab17ce914610191578063bc40ebb8146101e6578063c87b56dd146101af578063d2adbe79146101915763e985e9c51461013157600080fd5b3461018c57604036600319011261018c5761014a611d55565b610152611d6b565b9060018060a01b0316600052600560205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b600080fd5b3461018c57600036600319011261018c576020600854604051908152f35b3461018c57602036600319011261018c576101e26101ce6004356122f1565b604051918291602083526020830190611da4565b0390f35b3461018c57602036600319011261018c57600435600060c060405161020a81611e3d565b82815282602082015260606040820152606080820152606060808201528260a0820152015280600052600260205260018060a01b0360406000205416156103d9576000818152600c6020908152604080832080546001909101546001600160a01b039182168552600d84528285209116845290915290205481900361039457600052600c60205260406000206040516102a281611e3d565b81546001600160a01b03908116825260018301541660208201908152916102cb60028201611e79565b604083019081526103816102e160038401611e79565b6060850190815261036e6102f760048601611e79565b916080870192835261035b60ff600660058901549860a08b01998a520154169560c089019615158752604051998a9960208b5260018060a01b0390511660208b015260018060a01b0390511660408a01525160e060608a0152610100890190611da4565b9051878203601f19016080890152611da4565b9051858203601f190160a0870152611da4565b915160c084015251151560e08301520390f35b60405162461bcd60e51b815260206004820152601c60248201527f54657374696d6f6e69616c20686173206265656e2064656c65746564000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f54657374696d6f6e69616c20646f6573206e6f742065786973740000000000006044820152606490fd5b3461018c57608036600319011261018c57610437611d55565b61043f611d6b565b606435916001600160401b03831161018c573660238401121561018c5761047361047d933690602481600401359101611f65565b91604435916121a3565b005b3461018c57604036600319011261018c57610498611d55565b602435908115159081830361018c576001600160a01b0316918215610514576104e69033600052600560205260406000208460005260205260406000209060ff801983541691151516179055565b6040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b82630b61174360e31b60005260045260246000fd5b3461018c57600036600319011261018c57604051600060015461054b81611e03565b80845290600181169081156105d25750600114610573575b6101e2836101ce81850382611e58565b600160009081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6939250905b8082106105b8575090915081016020016101ce610563565b9192600181602092548385880101520191019092916105a0565b60ff191660208086019190915291151560051b840190910191506101ce9050610563565b3461018c57602036600319011261018c576004356000818152600260205260409020546001600160a01b031633036106e1576000818152600c60209081526040808320546001600160a01b0316808452600d83528184203385529092529091205482900361069c577faf1124c3e9482c81914cfd7af9eff6d985406bab38bdbb6fefc7bc3d8614773f9161068e60409233908361235b565b8151908152336020820152a1005b60405162461bcd60e51b815260206004820152601b60248201527f54657374696d6f6e69616c20616c72656164792064656c6574656400000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920726563697069656e742063616e2064656c657465000000000000006044820152606490fd5b3461018c57602036600319011261018c576001600160a01b03610747611d55565b1680156107665760005260036020526020604060002054604051908152f35b6322718ad960e21b600052600060045260246000fd5b3461018c57602036600319011261018c57602061079a600435612324565b6040516001600160a01b039091168152f35b3461018c57602036600319011261018c576001600160a01b036107cd611d55565b16600052600a6020526020604060002054604051908152f35b3461018c57600036600319011261018c576020600954604051908152f35b3461018c57606036600319011261018c576004356001600160401b03811161018c57610834903690600401611f1d565b906024356001600160401b03811161018c57610854903690600401611f1d565b90916044356001600160401b03811161018c57610875903690600401611f1d565b9433600052600e60205261088d604060002054611e03565b159460405194606086018681106001600160401b03821117610aef576108d7956108c8946108bf926040523691611f65565b86523691611f65565b94602084019586523691611f65565b926040820193845233600052600e602052604060002091518051906001600160401b038211610aef57819061090c8554611e03565b601f8111610c33575b50602090601f8311600114610bce57600092610bc3575b50508160011b916000199060031b1c19161782555b51805160018301916001600160401b038211610aef576109618354611e03565b601f8111610b7b575b50602090601f8311600114610b105760029493929160009183610b05575b50508160011b916000199060031b1c19161790555b0191519182516001600160401b038111610aef576109bb8254611e03565b601f8111610aa7575b506020601f8211600114610a425781929394600092610a37575b50508160011b916000199060031b1c19161790555b610a24575b7fbe4ec58a792f909e102ee3d745d0c3b34a4d437a54d903c4db098d31c556422f6020604051338152a1005b610a2f600854612150565b6008556109f8565b0151905084806109de565b601f1982169083600052806000209160005b818110610a8f57509583600195969710610a76575b505050811b0190556109f3565b015160001960f88460031b161c19169055848080610a69565b9192602060018192868b015181550194019201610a54565b826000526020600020601f830160051c81019160208410610ae5575b601f0160051c01905b818110610ad957506109c4565b60008155600101610acc565b9091508190610ac3565b634e487b7160e01b600052604160045260246000fd5b015190508780610988565b90601f1983169184600052816000209260005b818110610b63575091600193918560029897969410610b4a575b505050811b01905561099d565b015160001960f88460031b161c19169055878080610b3d565b92936020600181928786015181550195019301610b23565b836000526020600020601f840160051c81019160208510610bb9575b601f0160051c01905b818110610bad575061096a565b60008155600101610ba0565b9091508190610b97565b01519050868061092c565b60008681528281209350601f198516905b818110610c1b5750908460019594939210610c02575b505050811b018255610941565b015160001960f88460031b161c19169055868080610bf5565b92936020600181928786015181550195019301610bdf565b909150846000526020600020601f840160051c81019160208510610c7c575b90601f859493920160051c01905b818110610c6d5750610915565b60008155849350600101610c60565b9091508190610c52565b3461018c5760a036600319011261018c57610c9f611d55565b6024356001600160401b03811161018c57610cbe903690600401611f1d565b916044356001600160401b03811161018c57610cde903690600401611f1d565b926064356001600160401b03811161018c57610cfe903690600401611f1d565b9590946084356001600160401b03811161018c57610dcf82610dc98587610d8e8b8e8e8160488f8a90610d38610dd89e3690600401611f1d565b9c909a806040519b8c9a6bffffffffffffffffffffffff199060601b1660208c01523360601b60348c0152868b01378801918483016000815237010191600083528237016000815203601f198101835282611e58565b602081519101207f19457468657265756d205369676e6564204d6573736167653a0a333200000000600052601c52603c600020923691611f65565b90612434565b90929192612470565b6001600160a01b038681169116036118e8576001600160a01b0385166000908152600d6020908152604080832033845290915281205480151598919590896118d2575b50610e27600754612150565b978860075533156118bc576000898152600260205260408120546001600160a01b031661187757898152600260205260408120546001600160a01b0316801515918b9083611842575b33808252600360209081526040808420805460010190558484526002909152822080546001600160a01b031916821790559083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9080a45061182c57610f0f610f1e92610f0060405198610ee48a611e3d565b6001600160a01b038c168a523360208b01908152983691611f65565b95604089019687523691611f65565b92606087019384523691611f65565b608085019081524260a08601908152600160c0870181815260008b8152600c60205260409020975188546001600160a01b03199081166001600160a01b03928316178a55975192890180549098169216919091179095559251805191929160028701916001600160401b038211610aef578190610f9b8454611e03565b601f81116117d9575b50602090601f831160011461177457600092611769575b50508160011b916000199060031b1c19161790555b51805160038601916001600160401b038211610aef578190610ff28454611e03565b601f8111611716575b50602090601f83116001146116b1576000926116a6575b50508160011b916000199060031b1c19161790555b51805160048501916001600160401b038211610aef576110478354611e03565b601f811161165e575b50602090601f83116001146115ee5791806110a597969492600696946000926115e3575b50508160011b916000199060031b1c19161790555b51600584015551151591019060ff801983541691151516179055565b336000908152600a602052604090208054908168010000000000000000811015610aef576110dd816110f69360018994018155612175565b90919082549060031b91821b91600019901b1916179055565b6000848152600b60209081526040808320939093556001600160a01b0385168252600d8152828220338352905220839055156115d0575b81600052600c60205260406000209260405161114881611e3d565b84546001600160a01b039081168252600186015416602082019081529461117160028201611e79565b906040830191825261118560038201611e79565b906060840191825261119960048201611e79565b6080850190815260ff600660058401549360a088019485520154169260c0860193151584526111fd6111f06111e06111d08c6124f8565b98516001600160a01b0316612667565b9b516001600160a01b0316612667565b95519151925193516124f8565b9351600090156115a95750604051611216604082611e58565b60048152637472756560e01b6020820152945b6040519a8b976b3d913a37b5b2b724b2111d1160a11b60208a015280519081602c8b01916020019161125a92611d81565b88016b11161139b2b73232b9111d1160a11b602c8201528151918260388301916020019161128792611d81565b01602c016d1116113932b1b2b4bb32b9111d1160911b600c82015281519182601a830191602001916112b892611d81565b01600c016c11161131b7b73a32b73a111d1160991b600e82015281519182601b830191602001916112e892611d81565b01600e016e11161133b4bb32b92730b6b2911d1160891b600d82015281519182601c8301916020019161131a92611d81565b01600d016f111611383937b334b632aab936111d1160811b600f82015281519182601f8301916020019161134d92611d81565b01600f016e1116113a34b6b2b9ba30b6b8111d1160891b601082015281519182601f8301916020019161137f92611d81565b016010016d1116113b32b934b334b2b2111d1160911b600f82015281519182601d830191602001916113b092611d81565b01600f0161227d60f01b600e82015203600e01601d19810185526002016113d79085611e58565b826000526006602052604060002084516001600160401b038111610aef576113ff8254611e03565b601f8111611561575b50806020968790601f83116001146114fd576000926114f2575b50508160011b916000199060031b1c19161790555b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce784604051858152a17f9b09e829d78f88a15b1ae45769958983b0d2685486bbb34e98013c03fe17a180606060405185815260018060a01b03851687820152336040820152a16114ab575b50604051908152f35b604080516001600160a01b039092168252338483015281018290527fc18cfb482b914e0d363259c5d2a3bfc28e241e5bc5ebc5485428e2adc1262c4490606090a1826114a2565b015190508780611422565b60008581528281209350601f198516905b81811061154a5750908460019594939210611531575b505050811b019055611437565b015160001960f88460031b161c19169055878080611524565b92938a60018192878601518155019501930161150e565b826000526020600020601f830160051c8101916020841061159f575b601f0160051c01905b8181106115935750611408565b60008155600101611586565b909150819061157d565b506040516115b8604082611e58565b600581526466616c736560d81b602082015294611229565b6115db600954612150565b60095561112d565b015190508c80611074565b90601f1983169184600052816000209260005b8181106116465750926001928592600698966110a59b9a98961061162d575b505050811b019055611089565b015160001960f88460031b161c191690558c8080611620565b92936020600181928786015181550195019301611601565b836000526020600020601f840160051c8101916020851061169c575b601f0160051c01905b8181106116905750611050565b60008155600101611683565b909150819061167a565b015190508b80611012565b60008581528281209350601f198516905b8181106116fe57509084600195949392106116e5575b505050811b019055611027565b015160001960f88460031b161c191690558b80806116d8565b929360206001819287860151815501950193016116c2565b909150836000526020600020601f840160051c8101916020851061175f575b90601f859493920160051c01905b8181106117505750610ffb565b60008155849350600101611743565b9091508190611735565b015190508c80610fbb565b60008581528281209350601f198516905b8181106117c157509084600195949392106117a8575b505050811b019055610fd0565b015160001960f88460031b161c191690558c808061179b565b92936020600181928786015181550195019301611785565b909150836000526020600020601f840160051c81019160208510611822575b90601f859493920160051c01905b8181106118135750610fa4565b60008155849350600101611806565b90915081906117f8565b6339e3563760e11b600052600060045260246000fd5b600082815260046020526040902080546001600160a01b03191690558281526003602052604081208054600019019055610e70565b60405162461bcd60e51b815260206004820152601c60248201527f546f6b656e7320617265206e6f6e2d7472616e736665727261626c65000000006044820152606490fd5b633250574960e11b600052600060045260246000fd5b95506118e260019688339161235b565b89610e1b565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b3461018c5761047d61193236611dc9565b9060405192611942602085611e58565b600084526121a3565b3461018c57602036600319011261018c576001600160a01b0361196c611d55565b16600052600e6020526119ba60406000206101e261198982611e79565b916119c86119a5600261199e60018501611e79565b9301611e79565b91604051958695606087526060870190611da4565b908582036020870152611da4565b908382036040850152611da4565b3461018c5761047d6119e736611dc9565b91611f9c565b3461018c57604036600319011261018c57611a06611d55565b602435611a1281612324565b33151580611ac9575b80611a9b575b611a865781906001600160a01b0384811691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4600090815260046020526040902080546001600160a01b0319166001600160a01b03909216919091179055005b63a9fbf51f60e01b6000523360045260246000fd5b506001600160a01b038116600090815260056020908152604080832033845290915290205460ff1615611a21565b506001600160a01b038116331415611a1b565b3461018c57602036600319011261018c57600435611af981612324565b506000526004602052602060018060a01b0360406000205416604051908152f35b3461018c57600036600319011261018c5760405160008054611b3b81611e03565b80845290600181169081156105d25750600114611b62576101e2836101ce81850382611e58565b60008080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563939250905b808210611ba5575090915081016020016101ce610563565b919260018160209254838588010152019101909291611b8d565b3461018c57602036600319011261018c5760043563ffffffff60e01b811680910361018c57602090632483248360e11b8114908115611c04575b506040519015158152f35b6380ac58cd60e01b811491508115611c36575b8115611c25575b5082611bf9565b6301ffc9a760e01b14905082611c1e565b635b5e139f60e01b81149150611c17565b3461018c57604036600319011261018c57611c60611d55565b611c68611d6b565b6001600160a01b039182166000908152600d60209081526040808320939094168252918252829020548251811515815291820152f35b3461018c57602036600319011261018c576001600160a01b03611cbf611d55565b16600052600a60205260406000209081548082526020820190819360005260206000209060005b818110611d3f5750505081611cfc910382611e58565b6040519182916020830190602084525180915260408301919060005b818110611d26575050500390f35b8251845285945060209384019390920191600101611d18565b8254845260209093019260019283019201611ce6565b600435906001600160a01b038216820361018c57565b602435906001600160a01b038216820361018c57565b60005b838110611d945750506000910152565b8181015183820152602001611d84565b90602091611dbd81518092818552858086019101611d81565b601f01601f1916010190565b606090600319011261018c576004356001600160a01b038116810361018c57906024356001600160a01b038116810361018c579060443590565b90600182811c92168015611e33575b6020831014611e1d57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611e12565b60e081019081106001600160401b03821117610aef57604052565b90601f801991011681019081106001600160401b03821117610aef57604052565b9060405191826000825492611e8d84611e03565b8084529360018116908115611efb5750600114611eb4575b50611eb292500383611e58565b565b90506000929192526020600020906000915b818310611edf575050906020611eb29282010138611ea5565b6020919350806001915483858901015201910190918492611ec6565b905060209250611eb294915060ff191682840152151560051b82010138611ea5565b9181601f8401121561018c578235916001600160401b03831161018c576020838186019501011161018c57565b6001600160401b038111610aef57601f01601f191660200190565b929192611f7182611f4a565b91611f7f6040519384611e58565b82948184528183011161018c578281602093846000960137010152565b6001600160a01b03909116919082156118bc576000828152600260205260408120549093906001600160a01b031661187757828452600260205260408420546001600160a01b0316938391908590331515806120b8575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9082612083575b83815260036020526040812060018154019055848152600260205260408120846bffffffffffffffffffffffff60a01b82541617905580a46001600160a01b031680830361206957505050565b6364283d7b60e01b60005260045260245260445260646000fd5b600085815260046020526040902080546001600160a01b0319169055828152600360205260408120805460001901905561201c565b915091925080612101575b156120d2579084849238611ff3565b8390856120eb57602491637e27328960e01b8252600452fd5b60449163177e802f60e01b825233600452602452fd5b50338514801561212f575b806120c35750838152600460205260408120546001600160a01b031633146120c3565b5084815260056020908152604080832033845290915281205460ff1661210c565b600019811461215f5760010190565b634e487b7160e01b600052601160045260246000fd5b805482101561218d5760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b92916121b0818386611f9c565b813b6121bd575b50505050565b604051630a85bd0160e11b81523360048201526001600160a01b0394851660248201526044810191909152608060648201529216919060209082908190612208906084830190611da4565b03816000865af180916000916122a7575b509061227257503d1561226b573d61223081611f4a565b9061223e6040519283611e58565b81523d6000602083013e5b805190816122665782633250574960e11b60005260045260246000fd5b602001fd5b6060612249565b6001600160e01b03191663757a42ff60e11b016122935750388080806121b7565b633250574960e11b60005260045260246000fd5b6020813d6020116122e9575b816122c060209383611e58565b810103126122e55751906001600160e01b0319821682036122e2575038612219565b80fd5b5080fd5b3d91506122b3565b6122fa81612324565b5060005260066020526123106040600020611e79565b6000604051612320602082611e58565b5290565b6000818152600260205260409020546001600160a01b0316908115612347575090565b637e27328960e01b60005260045260246000fd5b6001600160a01b039182166000908152600d60209081526040808320949095168252928352838120819055600a8352838120828252600b90935292909220548154600019810190811161215f57808203612400575b5050805480156123ea5760001901906123c98282612175565b8154906000199060031b1b1916905555600052600b60205260006040812055565b634e487b7160e01b600052603160045260246000fd5b61240a9083612175565b90549060031b1c61241f816110dd8486612175565b600052600b60205260406000205538806123b0565b81519190604183036124655761245e92506020820151906060604084015193015160001a90612734565b9192909190565b505060009160029190565b91909160048110156124e2578061248657509050565b6000600182036124a15763f645eedf60e01b60005260046000fd5b50600281036124bf578263fce698f760e01b60005260045260246000fd5b90916003600092146124cf575050565b6335e2f38360e21b825260045260249150fd5b634e487b7160e01b600052602160045260246000fd5b8060009172184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b821015612644575b806d04ee2d6d415b85acef8100000000600a921015612629575b662386f26fc10000811015612615575b6305f5e100811015612604575b6127108110156125f5575b60648110156125e7575b10156125dc575b600a6021600184019361258085611f4a565b9461258e6040519687611e58565b80865261259d601f1991611f4a565b013660208701378401015b60001901916f181899199a1a9b1b9c1cb0b131b232b360811b8282061a83530480156125d757600a90916125a8565b505090565b60019091019061256e565b606460029104930192612567565b6127106004910493019261255d565b6305f5e10060089104930192612552565b662386f26fc1000060109104930192612545565b6d04ee2d6d415b85acef810000000060209104930192612535565b506040915072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b810461251b565b604051906001600160a01b031680612680606084611e58565b602a835260208301604036823783511561218d576030905382516001101561218d576078602184015360295b600181116126d657506126bd575090565b63e22e27eb60e01b600052600452601460245260446000fd5b90600f8116601081101561218d576000855184101561272057506f181899199a1a9b1b9c1cb0b131b232b360811b901a8483016020015360041c90801561215f57600019016126ac565b634e487b7160e01b81526032600452602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116127bd579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156127b1576000516001600160a01b038116156127a55790600090600090565b50600090600190600090565b6040513d6000823e3d90fd5b5050506000916003919056fea2646970667358221220fc3e39421416012ba9daea33f8c0c8407b92f44f86fd030d65f9890f00f6909464736f6c634300081c0033";

Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Bytecode bump — confirm it matches the deployed address

Since bytecode changed, verify the deployed contract at the updated address matches this build (same compiler/metadata). This prevents interface/bytecode drift at runtime.


🏁 Script executed:

#!/bin/bash
# Quick sanity: check code present at the Scroll Sepolia address
# (Replace RPC if you use a different endpoint)
ADDR="0x344fe9f4bee36dadd4b584be8e9a968b1515d291"
curl -s -X POST https://sepolia-rpc.scroll.io \
  -H 'content-type: application/json' \
  --data "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getCode\",\"params\":[\"$ADDR\",\"latest\"]}" | jq -r '.result' | awk '{print (length>4?"OK: bytecode present":"ERR: empty code") }'

Length of output: 20


🏁 Script executed:

#!/bin/bash
set -e

# Path to the factory file
FILE="web/src/typechain-types/factories/VouchMe__factory.ts"

# Extract the expected bytecode from the source
EXPECTED=$(sed -n -E 's/const _bytecode *= *"?(0x[0-9a-f]+)"?;?/\1/p' "$FILE")

# Deployed contract address on Scroll Sepolia
ADDR="0x344fe9f4bee36dadd4b584be8e9a968b1515d291"

# Fetch on‐chain bytecode
DEPLOYED=$(curl -s -X POST https://sepolia-rpc.scroll.io \
  -H 'content-type: application/json' \
  --data "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getCode\",\"params\":[\"$ADDR\",\"latest\"]}" \
  | jq -r '.result')

# Compare
if [ "$EXPECTED" = "$DEPLOYED" ]; then
  echo "OK: deployed bytecode matches the build"
else
  echo "ERR: deployed bytecode differs from the build"
fi

Length of output: 96


🏁 Script executed:

#!/bin/bash
set -e

# Locate the generated factory file
FILE=$(find . -type f -name 'VouchMe__factory.ts' | head -n1)
echo "Factory file: $FILE"

# Extract the first hex literal (the bytecode) from the file
EXPECTED=$(grep -o '0x[0-9a-f]\+' "$FILE" | head -n1)
echo "Expected bytecode prefix: ${EXPECTED:0:20}… (length ${#EXPECTED})"

# Fetch on‐chain bytecode from Scroll Sepolia
ADDR="0x344fe9f4bee36dadd4b584be8e9a968b1515d291"
DEPLOYED=$(curl -s -X POST https://sepolia-rpc.scroll.io \
  -H 'content-type: application/json' \
  --data "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getCode\",\"params\":[\"$ADDR\",\"latest\"]}" \
  | jq -r '.result')
echo "Deployed bytecode prefix: ${DEPLOYED:0:20}… (length ${#DEPLOYED})"

# Compare
if [ "$EXPECTED" = "$DEPLOYED" ]; then
  echo "OK: deployed bytecode matches this build"
else
  echo "ERR: deployed bytecode differs from this build"
  exit 1
fi

Length of output: 242


Bytecode mismatch: on-chain code at 0x344fe9f4bee36dadd4b584be8e9a968b1515d291 differs from the compiled _bytecode in web/src/typechain-types/factories/VouchMe__factory.ts (expected prefix 0x60806040523461033a…, got 0x608080604052600436…). Confirm the correct deployed address or re-deploy so the build’s bytecode matches runtime.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
web/src/utils/contract.ts (1)

4-6: Verified deployment addresses. Both entries match the latest artifacts:
– Scroll Sepolia (534351): 0x344fe9f4bee36dadd4b584be8e9a968b1515d291
– Ethereum Classic (61): 0xf01b3744cc6bdc115bf4a154a0041bce3251a932

Optional: normalize the Scroll Sepolia address to EIP-55 checksum for consistency:

- 534351: "0x344fe9f4bee36dadd4b584be8e9a968b1515d291"
+ 534351: "0x344Fe9F4bEE36DAdD4b584BE8E9a968B1515D291"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3b124e and c5ab599.

⛔ Files ignored due to path filters (1)
  • web/public/stability.svg is excluded by !**/*.svg
📒 Files selected for processing (4)
  • README.md (3 hunks)
  • contracts/broadcast/DeployVouchMe.s.sol/61/run-1759575443.json (1 hunks)
  • contracts/broadcast/DeployVouchMe.s.sol/61/run-latest.json (2 hunks)
  • web/src/utils/contract.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • contracts/broadcast/DeployVouchMe.s.sol/61/run-1759575443.json
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
README.md

6-6: Images should have alternate text (alt text)

(MD045, no-alt-text)

Comment on lines +4 to +7
<div align="center" style="display: flex; align-items: center; justify-content: center; gap: 16px;">
<img alt="Stability Nexus" src="web/public/stability.svg" width="175">
<img src="public/todo-project-logo.svg" width="175" />
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add alt text for the secondary logo image.

Line 6 renders an <img> without an alt attribute, tripping markdownlint MD045 and breaking screen-reader accessibility. Please add a meaningful alt (or alt="" if it’s purely decorative).

-  <img src="public/todo-project-logo.svg" width="175" />
+  <img alt="VouchMe logo" src="public/todo-project-logo.svg" width="175" />

Based on static analysis hints.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div align="center" style="display: flex; align-items: center; justify-content: center; gap: 16px;">
<img alt="Stability Nexus" src="web/public/stability.svg" width="175">
<img src="public/todo-project-logo.svg" width="175" />
</div>
<div align="center" style="display: flex; align-items: center; justify-content: center; gap: 16px;">
<img alt="Stability Nexus" src="web/public/stability.svg" width="175">
<img alt="VouchMe logo" src="public/todo-project-logo.svg" width="175" />
</div>
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

6-6: Images should have alternate text (alt text)

(MD045, no-alt-text)

🤖 Prompt for AI Agents
In README.md around lines 4 to 7 the second <img> tag lacks an alt attribute
causing markdownlint MD045 and accessibility issues; add an appropriate alt
attribute to the second image (e.g., alt="Todo Project logo") or use alt="" if
the graphic is purely decorative, ensuring the tag matches the existing
style/width attributes.

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.

1 participant