-
Notifications
You must be signed in to change notification settings - Fork 6
Update the landing page and add the total users and testimonials count #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughAdds 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
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
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 />
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this 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
_updateto 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 usingabi.encodewith domain separation
Replace theabi.encodePackedblock incontracts/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 stripshttps://, producing bare domains in posts. Usewindow.location.origineverywhere for share/copy. Optionally switch tohttps://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, keeptruncateLinkfor 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/totalTestimonialsonly increment and never decrement. If UI intends “ever created”, this is fine; if “active”, decrement on delete.
175-190: Redundant getters.Since
totalProfiles/totalTestimonialsarepublic, Solidity auto-generates getters. The explicit getters can be removed to save bytecode.
241-254: Profile “new” detection vianameis brittle (minor).Prefer a dedicated
mapping(address => bool) hasProfileflag 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 dataYou 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 layersMark 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 safetyUse 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 techAdd 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 mapUse 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 clientExport 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 floorsInitial 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
useReadContractcommonly returnsbigint. Convert defensively to avoid NaN and make intent clear. If you expect these to remain underNumber.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 readOptional: switch to
useReadContractsto fetch both totals in one request and set astaleTimeto 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 prefetchUsing 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
⛔ Files ignored due to path filters (1)
web/package-lock.jsonis 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.
isScrolledis 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 address0x344fe9f4bee36dadd4b584be8e9a968b1515d291for chain 534351 matches the mapping inweb/src/utils/contract.tsand the broadcast JSON; no conflicting.envor 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 callsgetTotalProfiles/getTotalTestimonials; undefined results fallback to 0 for older deploymentsweb/src/components/LandingPage/FeaturesSection.tsx (1)
32-36: Landing section refresh — LGTMSection 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 thatgetTotalProfiles,getTotalTestimonials,totalProfiles, andtotalTestimonialsare present inVouchMe__factory.tsand used inuseContractStats.ts.
| "clsx": "^2.1.1", | ||
| "ethers": "^6.13.5", | ||
| "framer-motion": "^12.4.7", | ||
| "framer-motion": "^12.23.12", |
There was a problem hiding this comment.
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 --jsonLength 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.
| const { address } = useAccount(); | ||
|
|
There was a problem hiding this comment.
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".
| onClick={() => router.push("/dashboard")} | ||
| > |
There was a problem hiding this comment.
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.
| 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]); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
|
|
||
| return ( | ||
| <span ref={ref} className={className}> | ||
| {count.toLocaleString()} |
There was a problem hiding this comment.
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.
| 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.
| 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", | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| const _bytecode = | ||
| "0x60806040523461033a57604080519081016001600160401b03811182821017610247576040908152601382527f566f7563684d652054657374696d6f6e69616c00000000000000000000000000602083015280519081016001600160401b038111828210176102475760405260058152640ac9eaa86960db1b602082015281516001600160401b03811161024757600054600181811c91168015610330575b602082101461022757601f81116102cc575b50602092601f8211600114610268579281929360009261025d575b50508160011b916000199060031b1c1916176000555b80516001600160401b03811161024757600154600181811c9116801561023d575b602082101461022757601f81116101c2575b50602091601f821160011461015e57918192600092610153575b50508160011b916000199060031b1c1916176001555b60405161271490816103408239f35b01519050388061012e565b601f198216926001600052806000209160005b8581106101aa57508360019510610191575b505050811b01600155610144565b015160001960f88460031b161c19169055388080610183565b91926020600181928685015181550194019201610171565b60016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061021d575b601f0160051c01905b8181106102115750610114565b60008155600101610204565b90915081906101fb565b634e487b7160e01b600052602260045260246000fd5b90607f1690610102565b634e487b7160e01b600052604160045260246000fd5b0151905038806100cb565b601f1982169360008052806000209160005b8681106102b4575083600195961061029b575b505050811b016000556100e1565b015160001960f88460031b161c1916905538808061028d565b9192602060018192868501518155019401920161027a565b600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c81019160208410610326575b601f0160051c01905b81811061031a57506100b0565b6000815560010161030d565b9091508190610304565b90607f169061009e565b600080fdfe608080604052600436101561001357600080fd5b60003560e01c9081626a9ad714611bd857508063010b113e14611b8157806301ffc9a714611af957806306fdde0314611a54578063081812fc14611a16578063095ea7b31461192757806323b872dd14611910578063332d56d71461188557806342842e0e1461185b57806343ec6bdd14610be2578063526403141461079c5780635f74900e146107625780636352211e1461073257806370a08231146106dc5780637f1e86ed146105ac57806395d89b41146104df578063a22cb46514610435578063b88d4fde146103d4578063bc40ebb81461019c578063c87b56dd146101655763e985e9c51461010557600080fd5b346101605760403660031901126101605761011e611c8f565b610126611ca5565b9060018060a01b0316600052600560205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b600080fd5b3461016057602036600319011261016057610198610184600435612206565b604051918291602083526020830190611cde565b0390f35b3461016057602036600319011261016057600435600060c06040516101c081611d77565b82815282602082015260606040820152606080820152606060808201528260a0820152015280600052600260205260018060a01b03604060002054161561038f576000818152600a6020908152604080832080546001909101546001600160a01b039182168552600b84528285209116845290915290205481900361034a57600052600a602052604060002060405161025881611d77565b81546001600160a01b039081168252600183015416602082019081529161028160028201611db3565b6040830190815261033761029760038401611db3565b606085019081526103246102ad60048601611db3565b916080870192835261031160ff600660058901549860a08b01998a520154169560c089019615158752604051998a9960208b5260018060a01b0390511660208b015260018060a01b0390511660408a01525160e060608a0152610100890190611cde565b9051878203601f19016080890152611cde565b9051858203601f190160a0870152611cde565b915160c084015251151560e08301520390f35b60405162461bcd60e51b815260206004820152601c60248201527f54657374696d6f6e69616c20686173206265656e2064656c65746564000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f54657374696d6f6e69616c20646f6573206e6f742065786973740000000000006044820152606490fd5b34610160576080366003190112610160576103ed611c8f565b6103f5611ca5565b606435916001600160401b038311610160573660238401121561016057610429610433933690602481600401359101611e9f565b91604435916120b8565b005b346101605760403660031901126101605761044e611c8f565b6024359081151590818303610160576001600160a01b03169182156104ca5761049c9033600052600560205260406000208460005260205260406000209060ff801983541691151516179055565b6040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b82630b61174360e31b60005260045260246000fd5b3461016057600036600319011261016057604051600060015461050181611d3d565b80845290600181169081156105885750600114610529575b6101988361018481850382611d92565b600160009081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6939250905b80821061056e57509091508101602001610184610519565b919260018160209254838588010152019101909291610556565b60ff191660208086019190915291151560051b840190910191506101849050610519565b34610160576020366003190112610160576004356000818152600260205260409020546001600160a01b03163303610697576000818152600a60209081526040808320546001600160a01b0316808452600b835281842033855290925290912054829003610652577faf1124c3e9482c81914cfd7af9eff6d985406bab38bdbb6fefc7bc3d8614773f91610644604092339083612270565b8151908152336020820152a1005b60405162461bcd60e51b815260206004820152601b60248201527f54657374696d6f6e69616c20616c72656164792064656c6574656400000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920726563697069656e742063616e2064656c657465000000000000006044820152606490fd5b34610160576020366003190112610160576001600160a01b036106fd611c8f565b16801561071c5760005260036020526020604060002054604051908152f35b6322718ad960e21b600052600060045260246000fd5b34610160576020366003190112610160576020610750600435612239565b6040516001600160a01b039091168152f35b34610160576020366003190112610160576001600160a01b03610783611c8f565b1660005260086020526020604060002054604051908152f35b34610160576060366003190112610160576004356001600160401b038111610160576107cc903690600401611e57565b6024356001600160401b038111610160576107eb903690600401611e57565b92906044356001600160401b0381116101605761080c903690600401611e57565b93909160405195606087018781106001600160401b03821117610a5857610857956108489461083f926040523691611e9f565b87523691611e9f565b92602085019384523691611e9f565b6040830190815233600052600c602052604060002092519283516001600160401b038111610a58576108898254611d3d565b601f8111610b9a575b50602094601f8211600114610b3557948192939495600092610b2a575b50508160011b916000199060031b1c19161781555b6001810192519283516001600160401b038111610a58576108e58254611d3d565b601f8111610ae2575b506020601f8211600114610a7957819060029596600092610a6e575b50508160011b916000199060031b1c19161790555b0190519081516001600160401b038111610a585761093d8254611d3d565b601f8111610a10575b50602092601f82116001146109ad57928192936000926109a2575b50508160011b916000199060031b1c19161790555b7fbe4ec58a792f909e102ee3d745d0c3b34a4d437a54d903c4db098d31c556422f6020604051338152a1005b015190508380610961565b601f1982169383600052806000209160005b8681106109f857508360019596106109df575b505050811b019055610976565b015160001960f88460031b161c191690558380806109d2565b919260206001819286850151815501940192016109bf565b826000526020600020601f830160051c81019160208410610a4e575b601f0160051c01905b818110610a425750610946565b60008155600101610a35565b9091508190610a2c565b634e487b7160e01b600052604160045260246000fd5b01519050868061090a565b601f1982169583600052816000209660005b818110610aca5750916002969791846001959410610ab1575b505050811b01905561091f565b015160001960f88460031b161c19169055868080610aa4565b83830151895560019098019760209384019301610a8b565b826000526020600020601f830160051c81019160208410610b20575b601f0160051c01905b818110610b1457506108ee565b60008155600101610b07565b9091508190610afe565b0151905085806108af565b601f1982169583600052806000209160005b888110610b8257508360019596979810610b69575b505050811b0181556108c4565b015160001960f88460031b161c19169055858080610b5c565b91926020600181928685015181550194019201610b47565b826000526020600020601f830160051c81019160208410610bd8575b601f0160051c01905b818110610bcc5750610892565b60008155600101610bbf565b9091508190610bb6565b346101605760a036600319011261016057610bfb611c8f565b6024356001600160401b03811161016057610c1a903690600401611e57565b6044356001600160401b03811161016057610c39903690600401611e57565b9290916064356001600160401b03811161016057610c5b903690600401611e57565b6084959195356001600160401b03811161016057610c7d903690600401611e57565b60405160608a811b6bffffffffffffffffffffffff1916602083019081523390911b60348301526001600160a01b038b169893899392909190888a604883013780878d818b8d8501818c6048830160008152370160480191600083528237016000815203601f1981018252610cf29082611d92565b5190207f19457468657265756d205369676e6564204d6573736167653a0a333200000000600052601c52603c600020913690610d2d92611e9f565b610d3691612349565b610d3f91612385565b6001600160a01b031603611822576000868152600b60209081526040808320338452909152902054801515989089611810575b505060075460001981146117fa57600101968760075533156117e4576000888152600260205260408120546001600160a01b031661179f57888152600260205260408120546001600160a01b0316801515918a908361176a575b33808252600360209081526040808420805460010190558484526002909152822080546001600160a01b031916821790559083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9080a45061175457610e61610e7092610e5260405198610e408a611d77565b8a8a5260208a0198338a523691611e9f565b95604089019687523691611e9f565b92606087019384523691611e9f565b608085019081524260a08601908152600160c0870181815260008a8152600a60205260409020975188546001600160a01b03199081166001600160a01b03928316178a55975192890180549098169216919091179095559251805191929160028701916001600160401b038211610a58578190610eed8454611d3d565b601f8111611701575b50602090601f831160011461169c57600092611691575b50508160011b916000199060031b1c19161790555b51805160038601916001600160401b038211610a58578190610f448454611d3d565b601f811161163e575b50602090601f83116001146115d9576000926115ce575b50508160011b916000199060031b1c19161790555b51805160048501916001600160401b038211610a5857610f998354611d3d565b601f8111611586575b50602090601f8311600114611516579180610ff7979694926006969460009261150b575b50508160011b916000199060031b1c19161790555b51600584015551151591019060ff801983541691151516179055565b3360009081526008602052604090208054908168010000000000000000811015610a585761102f81611048936001889401815561208a565b90919082549060031b91821b91600019901b1916179055565b82600052600960205260406000205580600052600b602052604060002060018060a01b0333166000526020528160406000205581600052600a60205260406000209260405161109681611d77565b84546001600160a01b03908116825260018601541660208201908152946110bf60028201611db3565b90604083019182526110d360038201611db3565b90606084019182526110e760048201611db3565b6080850190815260ff600660058401549360a088019485520154169260c08601931515845261114b61113e61112e61111e8c61240d565b98516001600160a01b031661257c565b9b516001600160a01b031661257c565b955191519251935161240d565b9351600090156114e45750604051611164604082611d92565b60048152637472756560e01b6020820152945b6040519a8b976b3d913a37b5b2b724b2111d1160a11b60208a015280519081602c8b0191602001916111a892611cbb565b88016b11161139b2b73232b9111d1160a11b602c820152815191826038830191602001916111d592611cbb565b01602c016d1116113932b1b2b4bb32b9111d1160911b600c82015281519182601a8301916020019161120692611cbb565b01600c016c11161131b7b73a32b73a111d1160991b600e82015281519182601b8301916020019161123692611cbb565b01600e016e11161133b4bb32b92730b6b2911d1160891b600d82015281519182601c8301916020019161126892611cbb565b01600d016f111611383937b334b632aab936111d1160811b600f82015281519182601f8301916020019161129b92611cbb565b01600f016e1116113a34b6b2b9ba30b6b8111d1160891b601082015281519182601f830191602001916112cd92611cbb565b016010016d1116113b32b934b334b2b2111d1160911b600f82015281519182601d830191602001916112fe92611cbb565b01600f0161227d60f01b600e82015203600e01601d19810185526002016113259085611d92565b826000526006602052604060002084516001600160401b038111610a585761134d8254611d3d565b601f811161149c575b50806020968790601f83116001146114385760009261142d575b50508160011b916000199060031b1c19161790555b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce784604051858152a17f9b09e829d78f88a15b1ae45769958983b0d2685486bbb34e98013c03fe17a18060606040518581528487820152336040820152a16113f1575b50604051908152f35b60607fc18cfb482b914e0d363259c5d2a3bfc28e241e5bc5ebc5485428e2adc1262c44916040519081523385820152836040820152a1826113e8565b015190508780611370565b60008581528281209350601f198516905b818110611485575090846001959493921061146c575b505050811b019055611385565b015160001960f88460031b161c1916905587808061145f565b92938a600181928786015181550195019301611449565b826000526020600020601f830160051c810191602084106114da575b601f0160051c01905b8181106114ce5750611356565b600081556001016114c1565b90915081906114b8565b506040516114f3604082611d92565b600581526466616c736560d81b602082015294611177565b015190508b80610fc6565b90601f1983169184600052816000209260005b81811061156e575092600192859260069896610ff79b9a989610611555575b505050811b019055610fdb565b015160001960f88460031b161c191690558b8080611548565b92936020600181928786015181550195019301611529565b836000526020600020601f840160051c810191602085106115c4575b601f0160051c01905b8181106115b85750610fa2565b600081556001016115ab565b90915081906115a2565b015190508a80610f64565b60008581528281209350601f198516905b818110611626575090846001959493921061160d575b505050811b019055610f79565b015160001960f88460031b161c191690558a8080611600565b929360206001819287860151815501950193016115ea565b909150836000526020600020601f840160051c81019160208510611687575b90601f859493920160051c01905b8181106116785750610f4d565b6000815584935060010161166b565b909150819061165d565b015190508b80610f0d565b60008581528281209350601f198516905b8181106116e957509084600195949392106116d0575b505050811b019055610f22565b015160001960f88460031b161c191690558b80806116c3565b929360206001819287860151815501950193016116ad565b909150836000526020600020601f840160051c8101916020851061174a575b90601f859493920160051c01905b81811061173b5750610ef6565b6000815584935060010161172e565b9091508190611720565b6339e3563760e11b600052600060045260246000fd5b600082815260046020526040902080546001600160a01b03191690558281526003602052604081208054600019019055610dcc565b60405162461bcd60e51b815260206004820152601c60248201527f546f6b656e7320617265206e6f6e2d7472616e736665727261626c65000000006044820152606490fd5b633250574960e11b600052600060045260246000fd5b634e487b7160e01b600052601160045260246000fd5b61181b913391612270565b8880610d72565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b346101605761043361186c36611d03565b906040519261187c602085611d92565b600084526120b8565b34610160576020366003190112610160576001600160a01b036118a6611c8f565b16600052600c6020526118f460406000206101986118c382611db3565b916119026118df60026118d860018501611db3565b9301611db3565b91604051958695606087526060870190611cde565b908582036020870152611cde565b908382036040850152611cde565b346101605761043361192136611d03565b91611ed6565b3461016057604036600319011261016057611940611c8f565b60243561194c81612239565b33151580611a03575b806119d5575b6119c05781906001600160a01b0384811691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4600090815260046020526040902080546001600160a01b0319166001600160a01b03909216919091179055005b63a9fbf51f60e01b6000523360045260246000fd5b506001600160a01b038116600090815260056020908152604080832033845290915290205460ff161561195b565b506001600160a01b038116331415611955565b3461016057602036600319011261016057600435611a3381612239565b506000526004602052602060018060a01b0360406000205416604051908152f35b346101605760003660031901126101605760405160008054611a7581611d3d565b80845290600181169081156105885750600114611a9c576101988361018481850382611d92565b60008080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563939250905b808210611adf57509091508101602001610184610519565b919260018160209254838588010152019101909291611ac7565b346101605760203660031901126101605760043563ffffffff60e01b811680910361016057602090632483248360e11b8114908115611b3e575b506040519015158152f35b6380ac58cd60e01b811491508115611b70575b8115611b5f575b5082611b33565b6301ffc9a760e01b14905082611b58565b635b5e139f60e01b81149150611b51565b3461016057604036600319011261016057611b9a611c8f565b611ba2611ca5565b6001600160a01b039182166000908152600b60209081526040808320939094168252918252829020548251811515815291820152f35b34610160576020366003190112610160576001600160a01b03611bf9611c8f565b16600052600860205260406000209081548082526020820190819360005260206000209060005b818110611c795750505081611c36910382611d92565b6040519182916020830190602084525180915260408301919060005b818110611c60575050500390f35b8251845285945060209384019390920191600101611c52565b8254845260209093019260019283019201611c20565b600435906001600160a01b038216820361016057565b602435906001600160a01b038216820361016057565b60005b838110611cce5750506000910152565b8181015183820152602001611cbe565b90602091611cf781518092818552858086019101611cbb565b601f01601f1916010190565b6060906003190112610160576004356001600160a01b038116810361016057906024356001600160a01b0381168103610160579060443590565b90600182811c92168015611d6d575b6020831014611d5757565b634e487b7160e01b600052602260045260246000fd5b91607f1691611d4c565b60e081019081106001600160401b03821117610a5857604052565b90601f801991011681019081106001600160401b03821117610a5857604052565b9060405191826000825492611dc784611d3d565b8084529360018116908115611e355750600114611dee575b50611dec92500383611d92565b565b90506000929192526020600020906000915b818310611e19575050906020611dec9282010138611ddf565b6020919350806001915483858901015201910190918492611e00565b905060209250611dec94915060ff191682840152151560051b82010138611ddf565b9181601f84011215610160578235916001600160401b038311610160576020838186019501011161016057565b6001600160401b038111610a5857601f01601f191660200190565b929192611eab82611e84565b91611eb96040519384611d92565b829481845281830111610160578281602093846000960137010152565b6001600160a01b03909116919082156117e4576000828152600260205260408120549093906001600160a01b031661179f57828452600260205260408420546001600160a01b031693839190859033151580611ff2575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9082611fbd575b83815260036020526040812060018154019055848152600260205260408120846bffffffffffffffffffffffff60a01b82541617905580a46001600160a01b0316808303611fa357505050565b6364283d7b60e01b60005260045260245260445260646000fd5b600085815260046020526040902080546001600160a01b03191690558281526003602052604081208054600019019055611f56565b91509192508061203b575b1561200c579084849238611f2d565b83908561202557602491637e27328960e01b8252600452fd5b60449163177e802f60e01b825233600452602452fd5b503385148015612069575b80611ffd5750838152600460205260408120546001600160a01b03163314611ffd565b5084815260056020908152604080832033845290915281205460ff16612046565b80548210156120a25760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b92916120c5818386611ed6565b813b6120d2575b50505050565b604051630a85bd0160e11b81523360048201526001600160a01b039485166024820152604481019190915260806064820152921691906020908290819061211d906084830190611cde565b03816000865af180916000916121bc575b509061218757503d15612180573d61214581611e84565b906121536040519283611d92565b81523d6000602083013e5b8051908161217b5782633250574960e11b60005260045260246000fd5b602001fd5b606061215e565b6001600160e01b03191663757a42ff60e11b016121a85750388080806120cc565b633250574960e11b60005260045260246000fd5b6020813d6020116121fe575b816121d560209383611d92565b810103126121fa5751906001600160e01b0319821682036121f757503861212e565b80fd5b5080fd5b3d91506121c8565b61220f81612239565b5060005260066020526122256040600020611db3565b6000604051612235602082611d92565b5290565b6000818152600260205260409020546001600160a01b031690811561225c575090565b637e27328960e01b60005260045260246000fd5b6001600160a01b039182166000908152600b602090815260408083209490951682529283528381208190556008835283812082825260099093529290922054815460001981019081116117fa57808203612315575b5050805480156122ff5760001901906122de828261208a565b8154906000199060031b1b1916905555600052600960205260006040812055565b634e487b7160e01b600052603160045260246000fd5b61231f908361208a565b90549060031b1c6123348161102f848661208a565b600052600960205260406000205538806122c5565b815191906041830361237a5761237392506020820151906060604084015193015160001a90612649565b9192909190565b505060009160029190565b91909160048110156123f7578061239b57509050565b6000600182036123b65763f645eedf60e01b60005260046000fd5b50600281036123d4578263fce698f760e01b60005260045260246000fd5b90916003600092146123e4575050565b6335e2f38360e21b825260045260249150fd5b634e487b7160e01b600052602160045260246000fd5b8060009172184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b821015612559575b806d04ee2d6d415b85acef8100000000600a92101561253e575b662386f26fc1000081101561252a575b6305f5e100811015612519575b61271081101561250a575b60648110156124fc575b10156124f1575b600a6021600184019361249585611e84565b946124a36040519687611d92565b8086526124b2601f1991611e84565b013660208701378401015b60001901916f181899199a1a9b1b9c1cb0b131b232b360811b8282061a83530480156124ec57600a90916124bd565b505090565b600190910190612483565b60646002910493019261247c565b61271060049104930192612472565b6305f5e10060089104930192612467565b662386f26fc100006010910493019261245a565b6d04ee2d6d415b85acef81000000006020910493019261244a565b506040915072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8104612430565b604051906001600160a01b031680612595606084611d92565b602a83526020830160403682378351156120a257603090538251600110156120a2576078602184015360295b600181116125eb57506125d2575090565b63e22e27eb60e01b600052600452601460245260446000fd5b90600f811660108110156120a2576000855184101561263557506f181899199a1a9b1b9c1cb0b131b232b360811b901a8483016020015360041c9080156117fa57600019016125c1565b634e487b7160e01b81526032600452602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116126d2579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156126c6576000516001600160a01b038116156126ba5790600090600090565b50600090600190600090565b6040513d6000823e3d90fd5b5050506000916003919056fea2646970667358221220fbd7d9e6490daa54cabed934df3f76331e83470ac06a047359e8a5bbbaafff5664736f6c634300081c0033"; | ||
| "0x60806040523461033a57604080519081016001600160401b03811182821017610247576040908152601382527f566f7563684d652054657374696d6f6e69616c00000000000000000000000000602083015280519081016001600160401b038111828210176102475760405260058152640ac9eaa86960db1b602082015281516001600160401b03811161024757600054600181811c91168015610330575b602082101461022757601f81116102cc575b50602092601f8211600114610268579281929360009261025d575b50508160011b916000199060031b1c1916176000555b80516001600160401b03811161024757600154600181811c9116801561023d575b602082101461022757601f81116101c2575b50602091601f821160011461015e57918192600092610153575b50508160011b916000199060031b1c1916176001555b6040516127ff90816103408239f35b01519050388061012e565b601f198216926001600052806000209160005b8581106101aa57508360019510610191575b505050811b01600155610144565b015160001960f88460031b161c19169055388080610183565b91926020600181928685015181550194019201610171565b60016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061021d575b601f0160051c01905b8181106102115750610114565b60008155600101610204565b90915081906101fb565b634e487b7160e01b600052602260045260246000fd5b90607f1690610102565b634e487b7160e01b600052604160045260246000fd5b0151905038806100cb565b601f1982169360008052806000209160005b8681106102b4575083600195961061029b575b505050811b016000556100e1565b015160001960f88460031b161c1916905538808061028d565b9192602060018192868501518155019401920161027a565b600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c81019160208410610326575b601f0160051c01905b81811061031a57506100b0565b6000815560010161030d565b9091508190610304565b90607f169061009e565b600080fdfe608080604052600436101561001357600080fd5b60003560e01c9081626a9ad714611c9e57508063010b113e14611c4757806301ffc9a714611bbf57806306fdde0314611b1a578063081812fc14611adc578063095ea7b3146119ed57806323b872dd146119d657806324b32f9f146107e6578063332d56d71461194b57806342842e0e1461192157806343ec6bdd14610c8657806352640314146108045780635eb3740e146107e65780635f74900e146107ac5780636352211e1461077c57806370a08231146107265780637f1e86ed146105f657806395d89b4114610529578063a22cb4651461047f578063b88d4fde1461041e578063bab17ce914610191578063bc40ebb8146101e6578063c87b56dd146101af578063d2adbe79146101915763e985e9c51461013157600080fd5b3461018c57604036600319011261018c5761014a611d55565b610152611d6b565b9060018060a01b0316600052600560205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b600080fd5b3461018c57600036600319011261018c576020600854604051908152f35b3461018c57602036600319011261018c576101e26101ce6004356122f1565b604051918291602083526020830190611da4565b0390f35b3461018c57602036600319011261018c57600435600060c060405161020a81611e3d565b82815282602082015260606040820152606080820152606060808201528260a0820152015280600052600260205260018060a01b0360406000205416156103d9576000818152600c6020908152604080832080546001909101546001600160a01b039182168552600d84528285209116845290915290205481900361039457600052600c60205260406000206040516102a281611e3d565b81546001600160a01b03908116825260018301541660208201908152916102cb60028201611e79565b604083019081526103816102e160038401611e79565b6060850190815261036e6102f760048601611e79565b916080870192835261035b60ff600660058901549860a08b01998a520154169560c089019615158752604051998a9960208b5260018060a01b0390511660208b015260018060a01b0390511660408a01525160e060608a0152610100890190611da4565b9051878203601f19016080890152611da4565b9051858203601f190160a0870152611da4565b915160c084015251151560e08301520390f35b60405162461bcd60e51b815260206004820152601c60248201527f54657374696d6f6e69616c20686173206265656e2064656c65746564000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f54657374696d6f6e69616c20646f6573206e6f742065786973740000000000006044820152606490fd5b3461018c57608036600319011261018c57610437611d55565b61043f611d6b565b606435916001600160401b03831161018c573660238401121561018c5761047361047d933690602481600401359101611f65565b91604435916121a3565b005b3461018c57604036600319011261018c57610498611d55565b602435908115159081830361018c576001600160a01b0316918215610514576104e69033600052600560205260406000208460005260205260406000209060ff801983541691151516179055565b6040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b82630b61174360e31b60005260045260246000fd5b3461018c57600036600319011261018c57604051600060015461054b81611e03565b80845290600181169081156105d25750600114610573575b6101e2836101ce81850382611e58565b600160009081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6939250905b8082106105b8575090915081016020016101ce610563565b9192600181602092548385880101520191019092916105a0565b60ff191660208086019190915291151560051b840190910191506101ce9050610563565b3461018c57602036600319011261018c576004356000818152600260205260409020546001600160a01b031633036106e1576000818152600c60209081526040808320546001600160a01b0316808452600d83528184203385529092529091205482900361069c577faf1124c3e9482c81914cfd7af9eff6d985406bab38bdbb6fefc7bc3d8614773f9161068e60409233908361235b565b8151908152336020820152a1005b60405162461bcd60e51b815260206004820152601b60248201527f54657374696d6f6e69616c20616c72656164792064656c6574656400000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920726563697069656e742063616e2064656c657465000000000000006044820152606490fd5b3461018c57602036600319011261018c576001600160a01b03610747611d55565b1680156107665760005260036020526020604060002054604051908152f35b6322718ad960e21b600052600060045260246000fd5b3461018c57602036600319011261018c57602061079a600435612324565b6040516001600160a01b039091168152f35b3461018c57602036600319011261018c576001600160a01b036107cd611d55565b16600052600a6020526020604060002054604051908152f35b3461018c57600036600319011261018c576020600954604051908152f35b3461018c57606036600319011261018c576004356001600160401b03811161018c57610834903690600401611f1d565b906024356001600160401b03811161018c57610854903690600401611f1d565b90916044356001600160401b03811161018c57610875903690600401611f1d565b9433600052600e60205261088d604060002054611e03565b159460405194606086018681106001600160401b03821117610aef576108d7956108c8946108bf926040523691611f65565b86523691611f65565b94602084019586523691611f65565b926040820193845233600052600e602052604060002091518051906001600160401b038211610aef57819061090c8554611e03565b601f8111610c33575b50602090601f8311600114610bce57600092610bc3575b50508160011b916000199060031b1c19161782555b51805160018301916001600160401b038211610aef576109618354611e03565b601f8111610b7b575b50602090601f8311600114610b105760029493929160009183610b05575b50508160011b916000199060031b1c19161790555b0191519182516001600160401b038111610aef576109bb8254611e03565b601f8111610aa7575b506020601f8211600114610a425781929394600092610a37575b50508160011b916000199060031b1c19161790555b610a24575b7fbe4ec58a792f909e102ee3d745d0c3b34a4d437a54d903c4db098d31c556422f6020604051338152a1005b610a2f600854612150565b6008556109f8565b0151905084806109de565b601f1982169083600052806000209160005b818110610a8f57509583600195969710610a76575b505050811b0190556109f3565b015160001960f88460031b161c19169055848080610a69565b9192602060018192868b015181550194019201610a54565b826000526020600020601f830160051c81019160208410610ae5575b601f0160051c01905b818110610ad957506109c4565b60008155600101610acc565b9091508190610ac3565b634e487b7160e01b600052604160045260246000fd5b015190508780610988565b90601f1983169184600052816000209260005b818110610b63575091600193918560029897969410610b4a575b505050811b01905561099d565b015160001960f88460031b161c19169055878080610b3d565b92936020600181928786015181550195019301610b23565b836000526020600020601f840160051c81019160208510610bb9575b601f0160051c01905b818110610bad575061096a565b60008155600101610ba0565b9091508190610b97565b01519050868061092c565b60008681528281209350601f198516905b818110610c1b5750908460019594939210610c02575b505050811b018255610941565b015160001960f88460031b161c19169055868080610bf5565b92936020600181928786015181550195019301610bdf565b909150846000526020600020601f840160051c81019160208510610c7c575b90601f859493920160051c01905b818110610c6d5750610915565b60008155849350600101610c60565b9091508190610c52565b3461018c5760a036600319011261018c57610c9f611d55565b6024356001600160401b03811161018c57610cbe903690600401611f1d565b916044356001600160401b03811161018c57610cde903690600401611f1d565b926064356001600160401b03811161018c57610cfe903690600401611f1d565b9590946084356001600160401b03811161018c57610dcf82610dc98587610d8e8b8e8e8160488f8a90610d38610dd89e3690600401611f1d565b9c909a806040519b8c9a6bffffffffffffffffffffffff199060601b1660208c01523360601b60348c0152868b01378801918483016000815237010191600083528237016000815203601f198101835282611e58565b602081519101207f19457468657265756d205369676e6564204d6573736167653a0a333200000000600052601c52603c600020923691611f65565b90612434565b90929192612470565b6001600160a01b038681169116036118e8576001600160a01b0385166000908152600d6020908152604080832033845290915281205480151598919590896118d2575b50610e27600754612150565b978860075533156118bc576000898152600260205260408120546001600160a01b031661187757898152600260205260408120546001600160a01b0316801515918b9083611842575b33808252600360209081526040808420805460010190558484526002909152822080546001600160a01b031916821790559083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9080a45061182c57610f0f610f1e92610f0060405198610ee48a611e3d565b6001600160a01b038c168a523360208b01908152983691611f65565b95604089019687523691611f65565b92606087019384523691611f65565b608085019081524260a08601908152600160c0870181815260008b8152600c60205260409020975188546001600160a01b03199081166001600160a01b03928316178a55975192890180549098169216919091179095559251805191929160028701916001600160401b038211610aef578190610f9b8454611e03565b601f81116117d9575b50602090601f831160011461177457600092611769575b50508160011b916000199060031b1c19161790555b51805160038601916001600160401b038211610aef578190610ff28454611e03565b601f8111611716575b50602090601f83116001146116b1576000926116a6575b50508160011b916000199060031b1c19161790555b51805160048501916001600160401b038211610aef576110478354611e03565b601f811161165e575b50602090601f83116001146115ee5791806110a597969492600696946000926115e3575b50508160011b916000199060031b1c19161790555b51600584015551151591019060ff801983541691151516179055565b336000908152600a602052604090208054908168010000000000000000811015610aef576110dd816110f69360018994018155612175565b90919082549060031b91821b91600019901b1916179055565b6000848152600b60209081526040808320939093556001600160a01b0385168252600d8152828220338352905220839055156115d0575b81600052600c60205260406000209260405161114881611e3d565b84546001600160a01b039081168252600186015416602082019081529461117160028201611e79565b906040830191825261118560038201611e79565b906060840191825261119960048201611e79565b6080850190815260ff600660058401549360a088019485520154169260c0860193151584526111fd6111f06111e06111d08c6124f8565b98516001600160a01b0316612667565b9b516001600160a01b0316612667565b95519151925193516124f8565b9351600090156115a95750604051611216604082611e58565b60048152637472756560e01b6020820152945b6040519a8b976b3d913a37b5b2b724b2111d1160a11b60208a015280519081602c8b01916020019161125a92611d81565b88016b11161139b2b73232b9111d1160a11b602c8201528151918260388301916020019161128792611d81565b01602c016d1116113932b1b2b4bb32b9111d1160911b600c82015281519182601a830191602001916112b892611d81565b01600c016c11161131b7b73a32b73a111d1160991b600e82015281519182601b830191602001916112e892611d81565b01600e016e11161133b4bb32b92730b6b2911d1160891b600d82015281519182601c8301916020019161131a92611d81565b01600d016f111611383937b334b632aab936111d1160811b600f82015281519182601f8301916020019161134d92611d81565b01600f016e1116113a34b6b2b9ba30b6b8111d1160891b601082015281519182601f8301916020019161137f92611d81565b016010016d1116113b32b934b334b2b2111d1160911b600f82015281519182601d830191602001916113b092611d81565b01600f0161227d60f01b600e82015203600e01601d19810185526002016113d79085611e58565b826000526006602052604060002084516001600160401b038111610aef576113ff8254611e03565b601f8111611561575b50806020968790601f83116001146114fd576000926114f2575b50508160011b916000199060031b1c19161790555b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce784604051858152a17f9b09e829d78f88a15b1ae45769958983b0d2685486bbb34e98013c03fe17a180606060405185815260018060a01b03851687820152336040820152a16114ab575b50604051908152f35b604080516001600160a01b039092168252338483015281018290527fc18cfb482b914e0d363259c5d2a3bfc28e241e5bc5ebc5485428e2adc1262c4490606090a1826114a2565b015190508780611422565b60008581528281209350601f198516905b81811061154a5750908460019594939210611531575b505050811b019055611437565b015160001960f88460031b161c19169055878080611524565b92938a60018192878601518155019501930161150e565b826000526020600020601f830160051c8101916020841061159f575b601f0160051c01905b8181106115935750611408565b60008155600101611586565b909150819061157d565b506040516115b8604082611e58565b600581526466616c736560d81b602082015294611229565b6115db600954612150565b60095561112d565b015190508c80611074565b90601f1983169184600052816000209260005b8181106116465750926001928592600698966110a59b9a98961061162d575b505050811b019055611089565b015160001960f88460031b161c191690558c8080611620565b92936020600181928786015181550195019301611601565b836000526020600020601f840160051c8101916020851061169c575b601f0160051c01905b8181106116905750611050565b60008155600101611683565b909150819061167a565b015190508b80611012565b60008581528281209350601f198516905b8181106116fe57509084600195949392106116e5575b505050811b019055611027565b015160001960f88460031b161c191690558b80806116d8565b929360206001819287860151815501950193016116c2565b909150836000526020600020601f840160051c8101916020851061175f575b90601f859493920160051c01905b8181106117505750610ffb565b60008155849350600101611743565b9091508190611735565b015190508c80610fbb565b60008581528281209350601f198516905b8181106117c157509084600195949392106117a8575b505050811b019055610fd0565b015160001960f88460031b161c191690558c808061179b565b92936020600181928786015181550195019301611785565b909150836000526020600020601f840160051c81019160208510611822575b90601f859493920160051c01905b8181106118135750610fa4565b60008155849350600101611806565b90915081906117f8565b6339e3563760e11b600052600060045260246000fd5b600082815260046020526040902080546001600160a01b03191690558281526003602052604081208054600019019055610e70565b60405162461bcd60e51b815260206004820152601c60248201527f546f6b656e7320617265206e6f6e2d7472616e736665727261626c65000000006044820152606490fd5b633250574960e11b600052600060045260246000fd5b95506118e260019688339161235b565b89610e1b565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b3461018c5761047d61193236611dc9565b9060405192611942602085611e58565b600084526121a3565b3461018c57602036600319011261018c576001600160a01b0361196c611d55565b16600052600e6020526119ba60406000206101e261198982611e79565b916119c86119a5600261199e60018501611e79565b9301611e79565b91604051958695606087526060870190611da4565b908582036020870152611da4565b908382036040850152611da4565b3461018c5761047d6119e736611dc9565b91611f9c565b3461018c57604036600319011261018c57611a06611d55565b602435611a1281612324565b33151580611ac9575b80611a9b575b611a865781906001600160a01b0384811691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4600090815260046020526040902080546001600160a01b0319166001600160a01b03909216919091179055005b63a9fbf51f60e01b6000523360045260246000fd5b506001600160a01b038116600090815260056020908152604080832033845290915290205460ff1615611a21565b506001600160a01b038116331415611a1b565b3461018c57602036600319011261018c57600435611af981612324565b506000526004602052602060018060a01b0360406000205416604051908152f35b3461018c57600036600319011261018c5760405160008054611b3b81611e03565b80845290600181169081156105d25750600114611b62576101e2836101ce81850382611e58565b60008080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563939250905b808210611ba5575090915081016020016101ce610563565b919260018160209254838588010152019101909291611b8d565b3461018c57602036600319011261018c5760043563ffffffff60e01b811680910361018c57602090632483248360e11b8114908115611c04575b506040519015158152f35b6380ac58cd60e01b811491508115611c36575b8115611c25575b5082611bf9565b6301ffc9a760e01b14905082611c1e565b635b5e139f60e01b81149150611c17565b3461018c57604036600319011261018c57611c60611d55565b611c68611d6b565b6001600160a01b039182166000908152600d60209081526040808320939094168252918252829020548251811515815291820152f35b3461018c57602036600319011261018c576001600160a01b03611cbf611d55565b16600052600a60205260406000209081548082526020820190819360005260206000209060005b818110611d3f5750505081611cfc910382611e58565b6040519182916020830190602084525180915260408301919060005b818110611d26575050500390f35b8251845285945060209384019390920191600101611d18565b8254845260209093019260019283019201611ce6565b600435906001600160a01b038216820361018c57565b602435906001600160a01b038216820361018c57565b60005b838110611d945750506000910152565b8181015183820152602001611d84565b90602091611dbd81518092818552858086019101611d81565b601f01601f1916010190565b606090600319011261018c576004356001600160a01b038116810361018c57906024356001600160a01b038116810361018c579060443590565b90600182811c92168015611e33575b6020831014611e1d57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611e12565b60e081019081106001600160401b03821117610aef57604052565b90601f801991011681019081106001600160401b03821117610aef57604052565b9060405191826000825492611e8d84611e03565b8084529360018116908115611efb5750600114611eb4575b50611eb292500383611e58565b565b90506000929192526020600020906000915b818310611edf575050906020611eb29282010138611ea5565b6020919350806001915483858901015201910190918492611ec6565b905060209250611eb294915060ff191682840152151560051b82010138611ea5565b9181601f8401121561018c578235916001600160401b03831161018c576020838186019501011161018c57565b6001600160401b038111610aef57601f01601f191660200190565b929192611f7182611f4a565b91611f7f6040519384611e58565b82948184528183011161018c578281602093846000960137010152565b6001600160a01b03909116919082156118bc576000828152600260205260408120549093906001600160a01b031661187757828452600260205260408420546001600160a01b0316938391908590331515806120b8575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9082612083575b83815260036020526040812060018154019055848152600260205260408120846bffffffffffffffffffffffff60a01b82541617905580a46001600160a01b031680830361206957505050565b6364283d7b60e01b60005260045260245260445260646000fd5b600085815260046020526040902080546001600160a01b0319169055828152600360205260408120805460001901905561201c565b915091925080612101575b156120d2579084849238611ff3565b8390856120eb57602491637e27328960e01b8252600452fd5b60449163177e802f60e01b825233600452602452fd5b50338514801561212f575b806120c35750838152600460205260408120546001600160a01b031633146120c3565b5084815260056020908152604080832033845290915281205460ff1661210c565b600019811461215f5760010190565b634e487b7160e01b600052601160045260246000fd5b805482101561218d5760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b92916121b0818386611f9c565b813b6121bd575b50505050565b604051630a85bd0160e11b81523360048201526001600160a01b0394851660248201526044810191909152608060648201529216919060209082908190612208906084830190611da4565b03816000865af180916000916122a7575b509061227257503d1561226b573d61223081611f4a565b9061223e6040519283611e58565b81523d6000602083013e5b805190816122665782633250574960e11b60005260045260246000fd5b602001fd5b6060612249565b6001600160e01b03191663757a42ff60e11b016122935750388080806121b7565b633250574960e11b60005260045260246000fd5b6020813d6020116122e9575b816122c060209383611e58565b810103126122e55751906001600160e01b0319821682036122e2575038612219565b80fd5b5080fd5b3d91506122b3565b6122fa81612324565b5060005260066020526123106040600020611e79565b6000604051612320602082611e58565b5290565b6000818152600260205260409020546001600160a01b0316908115612347575090565b637e27328960e01b60005260045260246000fd5b6001600160a01b039182166000908152600d60209081526040808320949095168252928352838120819055600a8352838120828252600b90935292909220548154600019810190811161215f57808203612400575b5050805480156123ea5760001901906123c98282612175565b8154906000199060031b1b1916905555600052600b60205260006040812055565b634e487b7160e01b600052603160045260246000fd5b61240a9083612175565b90549060031b1c61241f816110dd8486612175565b600052600b60205260406000205538806123b0565b81519190604183036124655761245e92506020820151906060604084015193015160001a90612734565b9192909190565b505060009160029190565b91909160048110156124e2578061248657509050565b6000600182036124a15763f645eedf60e01b60005260046000fd5b50600281036124bf578263fce698f760e01b60005260045260246000fd5b90916003600092146124cf575050565b6335e2f38360e21b825260045260249150fd5b634e487b7160e01b600052602160045260246000fd5b8060009172184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b821015612644575b806d04ee2d6d415b85acef8100000000600a921015612629575b662386f26fc10000811015612615575b6305f5e100811015612604575b6127108110156125f5575b60648110156125e7575b10156125dc575b600a6021600184019361258085611f4a565b9461258e6040519687611e58565b80865261259d601f1991611f4a565b013660208701378401015b60001901916f181899199a1a9b1b9c1cb0b131b232b360811b8282061a83530480156125d757600a90916125a8565b505090565b60019091019061256e565b606460029104930192612567565b6127106004910493019261255d565b6305f5e10060089104930192612552565b662386f26fc1000060109104930192612545565b6d04ee2d6d415b85acef810000000060209104930192612535565b506040915072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b810461251b565b604051906001600160a01b031680612680606084611e58565b602a835260208301604036823783511561218d576030905382516001101561218d576078602184015360295b600181116126d657506126bd575090565b63e22e27eb60e01b600052600452601460245260446000fd5b90600f8116601081101561218d576000855184101561272057506f181899199a1a9b1b9c1cb0b131b232b360811b901a8483016020015360041c90801561215f57600019016126ac565b634e487b7160e01b81526032600452602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116127bd579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156127b1576000516001600160a01b038116156127a55790600090600090565b50600090600190600090565b6040513d6000823e3d90fd5b5050506000916003919056fea2646970667358221220fc3e39421416012ba9daea33f8c0c8407b92f44f86fd030d65f9890f00f6909464736f6c634300081c0033"; | ||
|
|
There was a problem hiding this comment.
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"
fiLength 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
fiLength 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.
There was a problem hiding this 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): 0xf01b3744cc6bdc115bf4a154a0041bce3251a932Optional: 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
⛔ Files ignored due to path filters (1)
web/public/stability.svgis 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)
| <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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| <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.
Summary by CodeRabbit
New Features
Style
Chores