Skip to content

feat: harden orb frontend create and oracle interaction flows#31

Open
arunabha003 wants to merge 13 commits into
StabilityNexus:mainfrom
arunabha003:orb-ux-validation-states
Open

feat: harden orb frontend create and oracle interaction flows#31
arunabha003 wants to merge 13 commits into
StabilityNexus:mainfrom
arunabha003:orb-ux-validation-states

Conversation

@arunabha003
Copy link
Copy Markdown

@arunabha003 arunabha003 commented Mar 25, 2026

Addressed Issues:

  • improve create-oracle UX with clearer network/wallet readiness, stricter parameter validation, and proper submit-state handling
  • surface contract failures in the frontend with formatted revert messages, inline create errors, and a mounted global toaster
  • harden oracle interaction actions by validating submit/deposit/withdraw/governance inputs before transaction attempts
  • improve explorer and oracle detail usability with cleaner network-status messaging, address explorer links, and copy/open actions for contract addresses
  • add small app-level fixes for frontend stability, including favicon handling and the oracle-detail runtime fix

Validation

  • npm run build

Screenshots/Recordings:

  1. Action Validation for Deposit and Withdraw
Screenshot 2026-03-26 at 4 07 45 AM
  1. Oracle and Weight Token Explorer Links
Screenshot 2026-03-26 at 4 17 46 AM
  1. Create Oracle Failure Surfaced in UI
Screenshot 2026-03-26 at 4 16 48 AM

4.Inline Oracle Parameter Validation

Screenshot 2026-03-26 at 4 16 03 AM
  1. Explorer Network and Wallet Status UX
Screenshot 2026-03-26 at 4 15 04 AM

Additional Notes:

AI Usage Disclosure:

We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact. AI slop is strongly discouraged and may lead to banning and blocking. Do not spam our repos with AI slop.

Check one of the checkboxes below:

  • This PR does not contain AI-generated code at all.
  • This PR contains AI-generated code. I have read the AI Usage Policy and this PR complies with this policy. I have tested the code locally and I am responsible for it.

I have used the following AI models and tools: TODO

Checklist

  • My PR addresses a single issue, fixes a single bug or makes a single improvement.
  • My code follows the project's code style and conventions
  • If applicable, I have made corresponding changes or additions to the documentation
  • If applicable, I have made corresponding changes or additions to tests
  • My changes generate no new warnings or errors
  • I have joined the Discord server and I will share a link to this PR with the project maintainers there
  • I have read the Contribution Guidelines
  • Once I submit my PR, CodeRabbit AI will automatically review it and I will address CodeRabbit's comments.
  • I have filled this PR template completely and carefully, and I understand that my PR may be closed without review otherwise.

Summary by CodeRabbit

  • New Features

    • Chain explorer links for oracle and token addresses.
    • Network and wallet status panels on the Explorer.
    • Deployment status and improved create-oracle flow with contextual submit states.
    • Toast notification system in app chrome.
  • Improvements

    • Standardized, clearer error messages for read/write operations.
    • Numeric token input parsing and stronger validation with contextual hints.
    • Smarter action-state handling to prevent duplicate actions and refine button enablement.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

Centralizes contract error formatting; adds token-decimal-aware numeric parsing and validation flags; consolidates UI disabling via an overall in-flight flag; adds chain explorer URL support; improves oracle creation form validation and supported-chain awareness; integrates wallet/chain status into Explorer and renders a Toaster in layout.

Changes

Cohort / File(s) Summary
Interaction Client
app/[oracleId]/InteractionClient.tsx
Introduced token parsing (parseTokenAmount), raw BigInt amount flow, many derived validation flags (submit/deposit/withdraw/approve/vote), unified actionInFlight gating, standardized toast error descriptions via formatContractError, and chain explorer address links when available.
Oracle Creation Form
components/createOracle.tsx
Replaced imperative errors with memoized validationErrors, added hasSubmitted/touchedFields/submissionError, stricter numeric coercion (toBigIntOrZero), supported-network awareness, field-level error helpers, and formatContractError usage for submit failures; added "Deployment Status" UI.
Utilities: Errors & Addresses
utils/formatContractError.ts, utils/addresses.ts
Added formatContractError(error, fallback) to normalize viem/BaseError or Error messages; restructured OracleFactories to derive from OracleFactoryMetadata with labels, exported supportedOracleChainIds and getOracleChainLabel().
Explorer Page
app/explorer/page.tsx
Wired useAccount/useChainId/useChains to derive wallet and chain context, added "Network Status" and "Wallet Status" indicators, adjusted oracle-loading messages and CTA to use Button+Link, and broadened search placeholder copy.
Layout / Toaster
app/layout.tsx
Imported and rendered <Toaster /> inside RootLayout to enable client-side toast notifications.
Token-balance & UX adjustments
app/[oracleId]/InteractionClient.tsx (same file)
Treats missing locked/unlocked/balance/allowance as null rather than 0, updates operator availability logic and UX hint derivation for submit/deposit/withdraw/governance flows.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 Hopped through code with snacks in tow,

Errors trimmed and numbers grow,
Explorer doors now open wide,
Toasts announce each bumpy ride,
Supported chains — I hop with pride!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: hardening frontend validation, error handling, and UX for oracle creation and interaction flows, which are the core themes across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown

@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: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/`[oracleId]/InteractionClient.tsx:
- Around line 1151-1170: The icon-only explorer link and copy button currently
rely on title text and lack an explicit accessible name and button type; update
the anchor that renders the ExternalLink and the copy <button> (the element with
onClick={() => navigator.clipboard.writeText(oracle.address)}) to include
descriptive aria-label attributes (e.g., aria-label={`Open oracle
${oracle.address} in explorer`} and aria-label={`Copy oracle ${oracle.address}
address`}) and set type="button" on the copy <button>; apply the same changes to
the repeated block around the elements referenced at the later occurrence (lines
1183-1205) so both explorer and copy controls are discoverable by assistive
tech.
- Around line 414-417: The derived booleans currently treat unresolved RPC reads
as zero; change them to represent an explicit loading/unknown state by checking
for the presence of the raw read values before comparing. Specifically, in the
expressions that compute hasEnoughWalletBalance, hasEnoughUnlockedBalance,
allowanceRaw and needsApproval, first ensure depositAmountRaw, withdrawAmountRaw
and the read values (userTokenBalanceRaw, unlockedTokensRaw, tokenAllowanceData)
are non-null/defined (or use their associated isLoading flags) and only then
perform BigInt comparisons; otherwise set the derived flags to null/undefined
(or a separate "loading" state) so the UI can wait for the RPC results before
showing insufficiency. Apply the same guarding pattern wherever similar logic
appears (the other ranges referenced) to avoid flashing "not enough" while reads
are pending.
- Around line 408-409: Replace the fragile Number.parseFloat/Math.floor flow by
parsing the trimmed submitValue with parseUnits using PRICE_DECIMALS (same
pattern as parseTokenAmount) to produce a validated bigint; update the logic
that defines hasValidSubmitValue to check that parseUnits(submitValue.trim(),
PRICE_DECIMALS) succeeds and yields a non-negative bigint, store that bigint
(e.g., submitValueUnits) and use it directly when encoding or calling the
contract instead of re-encoding or converting via floating-point math; apply the
same change to the other occurrence that currently uses submitValueNumber (the
analogous code around the other validation/encoding site).

In `@components/createOracle.tsx`:
- Around line 79-81: The form stores errors in submissionError via
setSubmissionError but never renders it; update the Create Oracle component's
render near the submit CTA to display an inline error banner when
submissionError is non-null (e.g., conditionally render a <Banner/Alert> or
similar component next to the submit button using submissionError as its
message), and ensure the catch blocks that call setSubmissionError keep the
formatted message; also clear submissionError on successful submit or when the
user edits relevant fields (use setSubmissionError(null) in the success path and
on relevant onChange handlers or in setTouchedFields logic).
- Around line 106-118: The form collects and validates owner but never passes it
to the deployment call: update either the UI or the constructorArgs to avoid the
UX trap; specifically either remove/hide the owner input and related validation
(the owner state and OwnerInput usage) or include owner in the arguments passed
to createOracle by adjusting constructorArgs to match createOracle's expected
parameters if the contract actually accepts owner, and update any call sites of
createOracle accordingly; locate the owner state/validation and the
constructorArgs array in createOracle.tsx and ensure owner is either eliminated
from the form/validation and any labels updated to indicate it is ignored, or
added to constructorArgs and synchronized with createOracle invocation so the
supplied owner is actually used.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 778b07cc-ea59-43f8-acb2-6548ca0e6e6d

📥 Commits

Reviewing files that changed from the base of the PR and between bb0bf2b and 259ee46.

⛔ Files ignored due to path filters (1)
  • app/icon.svg is excluded by !**/*.svg
📒 Files selected for processing (6)
  • app/[oracleId]/InteractionClient.tsx
  • app/explorer/page.tsx
  • app/layout.tsx
  • components/createOracle.tsx
  • utils/addresses.ts
  • utils/formatContractError.ts

Comment thread app/[oracleId]/InteractionClient.tsx Outdated
Comment thread app/[oracleId]/InteractionClient.tsx Outdated
Comment thread app/[oracleId]/InteractionClient.tsx
Comment thread components/createOracle.tsx
Comment thread components/createOracle.tsx
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (3)
components/createOracle.tsx (3)

290-314: Consider cleanup for the setTimeout to avoid state updates on unmounted component.

If the user navigates away before the 5-second timeout completes, the callback will attempt to update state on an unmounted component. While this won't break functionality, it's a minor code smell.

♻️ Suggested fix using a ref
+ const isMountedRef = useRef(true)
+ 
+ useEffect(() => {
+   return () => { isMountedRef.current = false }
+ }, [])

  // Inside createOracle:
  setTimeout(async () => {
+   if (!isMountedRef.current) return
    try {
      // ... existing code
    } catch (err) {
+     if (!isMountedRef.current) return
      // ... existing code
    }
  }, 5000)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/createOracle.tsx` around lines 290 - 314, The setTimeout callback
that calls setOracleAddress, setSubmissionError, setSubmitted and toast can run
after the component unmounts; store the timeout id (from setTimeout) in a ref
(e.g., timerRef) when scheduling it and clear it in a cleanup effect (useEffect
return) or componentWillUnmount to avoid state updates on an unmounted
component; alternatively track mounted state in a ref (isMounted) and check it
before calling setOracleAddress/setSubmissionError/setSubmitted/toast so the
callback no-ops if the component is unmounted.

171-171: Remove unused owner from validationErrors dependency array.

The validationErrors memo includes owner in its dependency array, but owner is no longer used in the validation logic (it was removed when the field became read-only). This creates unnecessary re-computations when owner changes.

♻️ Suggested fix
-  }, [alpha, depositLock, description, halfLifeSeconds, name, owner, quorumBps, reward, weightToken, withdrawLock])
+  }, [alpha, depositLock, description, halfLifeSeconds, name, quorumBps, reward, weightToken, withdrawLock])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/createOracle.tsx` at line 171, The useMemo for validationErrors
still lists owner in its dependency array even though owner is no longer
referenced in the validation logic; remove owner from the dependency array of
validationErrors (the useMemo that computes validationErrors) so the memo only
depends on actual fields (alpha, depositLock, description, halfLifeSeconds,
name, quorumBps, reward, weightToken, withdrawLock) and avoid unnecessary
recomputations when owner changes.

287-302: Race condition in oracle lookup—consider waiting for transaction confirmation before reading state.

The polling approach is fragile because it assumes the last oracle in allOracles was just created by this user. If another user creates an oracle between the 5-second delay and your read, you'll get the wrong address.

Since createOracle returns the oracle address directly, the most robust fix is to wait for transaction confirmation using waitForTransactionReceipt and then parse the OracleCreated event (which contains the oracle address and is indexed by creator). Alternatively, query creatorOracleList(userAddress) to deterministically find your oracle after the transaction settles.

The current comment already flags this as a limitation, but for production use, implement proper receipt handling rather than polling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/createOracle.tsx` around lines 287 - 302, Replace the fragile
timeout/polling lookup of allOracles with deterministic receipt/event handling:
after calling createOracle, wait for the transaction receipt via
waitForTransactionReceipt (or the provider's wait method), parse the
OracleCreated event from the receipt to extract the oracle address (event name
OracleCreated, indexed creator) and call setOracleAddress with that value; as a
fallback you can query creatorOracleList(userAddress) after the receipt to find
the created oracle instead of reading allOracles. Ensure you locate the logic
around createOracle, the timeout block that reads allOracles, and replace it
with the receipt parsing or creatorOracleList query and then setOracleAddress.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@components/createOracle.tsx`:
- Around line 290-314: The setTimeout callback that calls setOracleAddress,
setSubmissionError, setSubmitted and toast can run after the component unmounts;
store the timeout id (from setTimeout) in a ref (e.g., timerRef) when scheduling
it and clear it in a cleanup effect (useEffect return) or componentWillUnmount
to avoid state updates on an unmounted component; alternatively track mounted
state in a ref (isMounted) and check it before calling
setOracleAddress/setSubmissionError/setSubmitted/toast so the callback no-ops if
the component is unmounted.
- Line 171: The useMemo for validationErrors still lists owner in its dependency
array even though owner is no longer referenced in the validation logic; remove
owner from the dependency array of validationErrors (the useMemo that computes
validationErrors) so the memo only depends on actual fields (alpha, depositLock,
description, halfLifeSeconds, name, quorumBps, reward, weightToken,
withdrawLock) and avoid unnecessary recomputations when owner changes.
- Around line 287-302: Replace the fragile timeout/polling lookup of allOracles
with deterministic receipt/event handling: after calling createOracle, wait for
the transaction receipt via waitForTransactionReceipt (or the provider's wait
method), parse the OracleCreated event from the receipt to extract the oracle
address (event name OracleCreated, indexed creator) and call setOracleAddress
with that value; as a fallback you can query creatorOracleList(userAddress)
after the receipt to find the created oracle instead of reading allOracles.
Ensure you locate the logic around createOracle, the timeout block that reads
allOracles, and replace it with the receipt parsing or creatorOracleList query
and then setOracleAddress.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f284f3df-f7eb-4d64-afa0-bde9d483f72a

📥 Commits

Reviewing files that changed from the base of the PR and between 259ee46 and c49bbdf.

📒 Files selected for processing (2)
  • app/[oracleId]/InteractionClient.tsx
  • components/createOracle.tsx

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