Refine scalar market validation and preview#113
Conversation
- Replace raw tick inputs with scalar min, max, and increment fields - Add form validation feedback and update scalar preview/deployment UX - Update tests for scalar parsing and market creation validation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- Reload UI when generated TypeScript output changes - Move market form validation notice inline and remove redundant error gating
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- Store categorical outcomes as a list and validate duplicate labels - Replace textarea input with per-outcome fields and add/remove controls - Update watcher logging and UI styling for the new flow
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- Reload the UI when TypeScript source files change - Remove the extra outcomes help text from market creation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- show approved REP and approval status in the migration UI - require allowance before preparing migration REP - improve migration revert messages and fork question ID handling
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- Add fork-state guard to security pool creation - Replace latest-question flow with reset after successful deploy - Update security pool UI to reflect forked-universe lock
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- Add oracle report browsing, dispute actions, and updated vault controls - Surface universe mismatch guidance in the security pool workflow - Harden isolated Anvil timestamp and snapshot handling
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- Fetch REP/ETH and REP/USDC prices for the overview UI - Add Uniswap V4 quoting with V3 fallback and formatting tweaks - Cover the new quoter logic with unit and integration tests
🛡️ Defender Against the Dark Arts5 issues found Specific file edit commands in permissions configuration📍 .claude/settings.local.json:23 The permissions list includes specific sed commands to edit ui/ts/components/SecurityPoolsOverviewSection.tsx. This is a severe security anti-pattern as it allows direct code modification without version control review, potentially enabling backdoors or insider threats. Permissions should define allowed actions, not prescribe specific file changes. Unrestricted bunx command execution permission📍 .claude/settings.local.json:27 The permission 'Bash(bunx:*)' allows execution of any package via bunx, which can lead to arbitrary code execution if a malicious or compromised package is run. This poses a significant supply chain risk and should be restricted to specific packages. Overly permissive WebFetch permissions to external domains📍 .claude/settings.local.json:26 Permissions allow WebFetch to multiple external domains (docs.uniswap.org, app.uniswap.org, gateway.thegraph.com). While these may be legitimate, such broad permissions can be abused for data exfiltration or downloading malicious content. Network access should be minimized and whitelisted to only necessary domains. Suspicious RPC endpoint configuration📍 ui/ts/tests/uniswapQuoter.integration.test.ts:14 The integration test uses a non-standard and suspicious RPC URL 'https://ethereum.dark.florist' for mainnet calls. This domain is not associated with any reputable Ethereum RPC provider (e.g., Infura, Alchemy, public nodes) and could be malicious. Using such an endpoint risks data exfiltration, manipulation of quotes, or monitoring of test activities, indicating a potential supply chain compromise or insider threat. Inconsistent naming in queuedOperation string literalThe value 'setSecurityBondsAllowance' uses plural 'Bonds' while other related fields like 'securityBondAllowanceAmount' use singular 'Bond'. This inconsistency could indicate a typographical error that might lead to runtime mismatches if the string values are used for logic control, potentially causing functional bugs or misrouting of operations. |
🔒 Security Reviewer10 issues found Overly broad bunx permission allows arbitrary code execution📍 .claude/settings.local.json:27 The permission pattern 'Bash(bunx:*)' grants the ability to execute any package via bunx, which runs arbitrary Node.js code. An attacker who can influence the AI assistant (e.g., via prompt injection) could run malicious code on the system, leading to full compromise. Arbitrary code execution via ANVIL_BIN environment variable📍 solidity/ts/testsuite/simulator/useIsolatedAnvilNode.ts:49 The resolveAnvilBinary function (lines 49-65) reads the ANVIL_BIN environment variable and returns it without validation. This value is used as the command in child_process.spawn (line 179). If an attacker can set ANVIL_BIN, they can execute arbitrary code with the test runner's privileges. Server-Side Request Forgery and data exfiltration via ANVIL_RPC environment variable📍 solidity/ts/testsuite/simulator/useIsolatedAnvilNode.ts:69 The getAnvilConnectionMode function (lines 69-84) reads the ANVIL_RPC environment variable and returns it as the RPC URL without validation. This URL is then used to connect to the Anvil node (lines 165-166) and all subsequent test traffic is routed through it. An attacker controlling ANVIL_RPC can exfiltrate data or perform SSRF attacks. Missing error handling for fs.watch leading to unhandled exceptions and process crashThe functions Lack of input validation for blockchain addresses and amounts📍 ui/ts/components/TradingSection.tsx:45 The trading form accepts user inputs for security pool address, amounts, and universe ID without any client-side validation. Malformed or malicious inputs (e.g., invalid Ethereum addresses, negative amounts, excessively large numbers) could be passed to the backend, potentially causing transaction failures, gas waste, or unexpected contract behavior. While validation should primarily occur at the smart contract level, client-side validation is a critical defense layer and usability safeguard against attacker-crafted transactions. Potential transaction replay or front-running due to missing nonce/hash binding📍 ui/ts/components/TradingSection.tsx:26 The component renders transaction details (UniverseLink and TransactionHashLink) after completion but does not display or bind the transaction to a specific nonce or block number. In a trading context, this could allow an attacker to observe a pending transaction and front-run it by submitting a competing transaction with higher gas. Additionally, without binding transactions to a unique user session or nonce, there's a theoretical risk of transaction replay if signature validation is insufficient on the contract side. The UI should surface nonce/chain context to users and enforce transaction uniqueness at the contract layer. Inconsistent OpenOracle address usage in approvals and dispute📍 ui/ts/hooks/useOpenOracleOperations.ts The approveToken1, approveToken2, and disputeReport functions obtain the target OpenOracle address via resolveOpenOracleAddress(), which uses the current form state or the loaded manager's address. However, the token data and report data used in these functions come from either the loaded manager or the loaded report. If the openOracleAddress form field is changed after loading these details (e.g., by loading a manager which overwrites the address, or by manual user edit), the transaction will be sent to an address that does not correspond to the oracle associated with the tokens or report. An attacker can exploit this inconsistency to trick a user into approving a malicious oracle or sending a dispute to a malicious oracle while the user believes they are interacting with a previously loaded trusted oracle. This could lead to unauthorized token transfers and financial loss. Lack of validation on approval amount in approveZoltarForkRep📍 ui/ts/hooks/useZoltarFork.ts:159 The approveZoltarForkRep function accepts an optional amount parameter without validating that it is non-negative. A negative bigint value could be interpreted as a large positive number when passed to the ERC20 approve function, potentially leading to an approval of the maximum possible token amount. This could be exploited if an attacker can influence the amount parameter, e.g., through UI input manipulation, resulting in unauthorized token spending. Insufficient validation of units and decimals parameters may cause denial of serviceThe function formatRoundedCurrencyBalance does not impose upper bounds on the units and decimals parameters. Large values can cause expensive bigint exponentiations (e.g., 10n ** BigInt(units) and 10n ** BigInt(effectiveDecimals)), potentially freezing the UI. An attacker who can influence these parameters (e.g., via malicious token configurations) could exploit this to launch a denial of service attack. Integer truncation in V4 quote due to unchecked amountIn📍 ui/ts/lib/uniswapQuoter.ts:66 The amountIn parameter in the quoteExactInput function is passed to the Uniswap V4 quoter contract as a uint128 without validation. Since JavaScript bigint can represent values larger than 2^128-1, truncation occurs during ABI encoding, resulting in an incorrect amount being quoted. This can be exploited by attackers to manipulate quote results, potentially causing significant financial loss when trades are executed based on these quotes. |
🐛 Bug Hunter55 issues found Incorrect escaping in sed replacement command📍 .claude/settings.local.json:24 The sed command added to modify SecurityPoolsOverviewSection.tsx at line 65 uses unnecessary backslashes to escape parentheses in the replacement string. The current replacement Extra hyphen in Notes section bullet points causing malformed MarkdownIn the 'Notes' section (lines 92-95), each bullet point incorrectly starts with '- -' instead of a single '-'. This breaks Markdown list formatting, resulting in list items that display an extra hyphen and are not recognized as proper list items. This typographical error affects documentation readability and must be fixed. Incorrect timestamp initialization and reset📍 solidity/ts/testsuite/simulator/AnvilWindowEthereum.ts:281 The variables currentTimestamp and snapshotTimestamp are initialized to 0n and reset to 0n in resetToCleanState, but Anvil's actual block timestamp after reset is non-zero. This causes getTime and getBlock to return 0 instead of the actual timestamp, leading to incorrect test behavior and potential failures in time-sensitive tests. Invalid RPC parameter format in evm_setNextBlockTimestamp fallback📍 solidity/ts/testsuite/simulator/AnvilWindowEthereum.ts:226 In manipulateTime for SetTimestamp, when the first evm_setNextBlockTimestamp call fails with 'timestamp is too big', the fallback call uses blockTimeManipulation.timeToSet.toString() which returns a decimal string. Ethereum JSON-RPC requires integer parameters to be hex strings with '0x' prefix, so this will cause an RPC error and failure to set the timestamp. Missing setTime call after resetToCleanState in isolated mode📍 solidity/ts/testsuite/simulator/useIsolatedAnvilNode.ts:219 In the error handling path of beforeEach, when anvilRevert fails with 'Resource not found', resetToCleanState is called to recover. However, for isolated mode, the timestamp is not reset to TEST_CHAIN_START_TIMESTAMP, while in the normal setup (beforeAll), the timestamp is explicitly set. This leads to an inconsistent state where the node's timestamp may not be as expected after recovery, potentially causing test failures that depend on specific block timestamps. Directory watchers lack error handling, risking uncaught exceptions and crashesThe functions watchDirectoryForTypeScriptOutputs and watchDirectoryForTypeScriptSources create fs.watch instances without attaching an 'error' event listener. If a watched directory is deleted or becomes inaccessible, fs.watch emits an error event which, if unhandled, will cause an uncaught exception and crash the watch process. An error handler should be added to log the error and attempt a graceful shutdown or recovery. Source TypeScript file watchers cause premature browser reloadsThe function refreshTypeScriptSourceWatchers sets up file watchers for every .ts file that call queueLiveReload as soon as the file changes. This triggers a browser reload before the TypeScript compiler has produced updated JavaScript output, potentially serving stale or syntactically invalid code. Only changes to compiled output (.js files) should cause reloads. These file watchers are unnecessary because directory watchers already detect new files, and the TypeScript watch process handles recompilation; their reload action is incorrect. Watcher refresh creates a gap with no active watchers, risking missed changesrefreshTypeScriptOutputWatchers and refreshTypeScriptSourceWatchers clear all existing watchers before creating new ones. This leaves a window of time—however brief—where no file system events are monitored. Any changes occurring during this gap will not be detected, leading to missed reloads or stale state. The refresh should be performed atomically: new watchers must be established before old ones are removed. Scalar slider fill misaligned with trackThe .scalar-slider-fill element's left property was changed from 0.85rem to 0. This causes the fill to start at the rail's padding edge instead of aligning with the track, which begins at 0.85rem. The fill should align exactly with the track background for correct visual representation of the slider value. 404 page layout broken by missing grid propertiesThe .not-found-shell container lost its grid-template-columns and align-items declarations in the diff. This changes the intended two-column layout (which positions the .not-found-mark and .not-found-copy side by side and aligns them to the bottom) into a single-column, top-aligned layout, breaking the visual design of the 404 page. These properties must be restored. Route content can be interacted with before wallet bootstrap completesThe condition for disabling route content originally included Misleading status detail when another deployment is in progress📍 ui/ts/components/DeploymentSection.tsx:11 The getStepStatus function returns the detail message 'Can deploy now.' for steps with no prerequisites, even if another step is currently being deployed (busyStepId is set). However, the deploy button is disabled globally when busyStepId is not undefined, causing a mismatch between the status message and actual deployability. This results in incorrect output that can confuse users. Undefined accountState access leads to runtime crashes📍 ui/ts/components/ForkAuctionSection.tsx:47 The component ForkAuctionSection accesses properties of the accountState prop without checking if it is defined. At line 47, accountState.chainId is used to compute isMainnet, which will throw a TypeError if accountState is undefined. Similarly, in multiple button disabled conditions (e.g., lines 260, 263, 286, 289, 295, 298, 312, 315, 329, 332, 342, 362), accountState.address is accessed directly. If accountState is undefined, these expressions cause runtime crashes during rendering or user interaction, breaking functionality. Missing required argument in onApproveZoltarForkRep call📍 ui/ts/components/ForkZoltarSection.tsx:105 The onApproveZoltarForkRep prop was updated to accept an optional bigint amount parameter, likely to specify the REP amount to approve. However, in the component, it is invoked without any argument (onClick={() => onApproveZoltarForkRep()}). Given the context of approving a REP threshold for forking, the call should pass the forkThreshold value from rootUniverse. Not passing the amount may result in the approval transaction using a default or zero amount, breaking the intended functionality where the user must approve at least the forkThreshold. Categorical outcomes validation error not displayed when outcomes array is empty📍 ui/ts/components/MarketCreateQuestionSection.tsx:163 When the categorical outcomes array is empty, the form validation sets Loading state styling class removed without replacement📍 ui/ts/components/MarketOverviewSection.tsx:44 The className 'market-overview-loading' was removed from the loading paragraph element, but the CSS rules targeting this class may no longer apply. This could cause the loading state to lose its intended visual styling (e.g., opacity, animation, or other indicators) even though the functional LoadingText component is still rendered. If the stylesheet relies on this specific class to indicate a loading state visually, the UI will not correctly signal the loading condition to users. Incorrect calculation of split limit in getMigrationOutcomeSplitLimit📍 ui/ts/components/MigrationOutcomeUniversesSection.tsx:20 The function getMigrationOutcomeSplitLimit is intended to compute the maximum equal allocation per selected child when splitting the migration balance. The current implementation only takes the minimum of remaining capacities (migrationBalance - heldBalance) among selected children, but ignores the global constraint that (perChildAmount × selectedCount) must not exceed migrationBalance. This can produce a split limit that, if used directly, would exceed the available migration balance, leading to over-allocation and potential transaction failures or incorrect state. The function should also consider migrationBalance divided by the number of selected children. Dispute & Swap button enabled in invalid states📍 ui/ts/components/OpenOracleSection.tsx:260 The disabled condition for the 'Dispute & Swap' button (line 260) only checks network connection and whether a report is loaded. It should also ensure that:
Non-functional anchor elements rendered for REP price source indicators when pool URL is unavailable📍 ui/ts/components/OverviewPanels.tsx:73 The component renders an anchor () element for REP/ETH and REP/USDC price source badges even when no pool URL exists for the given source version. For repEthSource='v4', href is set to undefined; similarly for repUsdcSource='v3'. This results in a non-clickable anchor that misleads users expecting a hyperlink. The element should be rendered as plain text (e.g., ) when no valid URL is available. Exported helper function may cause naming collision or misuse📍 ui/ts/components/Question.tsx:12 The function Hardcoded badge class for Loaded Escalation Game📍 ui/ts/components/ReportingSection.tsx:50 The badge class for the 'Loaded Escalation Game' EntityCard is hardcoded as 'ok', but it should dynamically reflect the escalation phase returned by getEscalationPhase. Using 'ok' for all phases misrepresents the state; for example, if the phase is 'Ended', the badge should not have the 'ok' class, which typically indicates an active or positive state. Hardcoded badge class for Latest Reporting Action📍 ui/ts/components/ReportingSection.tsx:129 The badge class for the 'Latest Reporting Action' EntityCard is hardcoded as 'ok', but it should vary based on the reporting outcome from reportingResult.outcome. A fixed 'ok' class is inappropriate for outcomes like 'Invalid', which should not be styled as positive, leading to misleading UI. Hardcoded badge text for Escalation Metrics📍 ui/ts/components/ReportingSection.tsx:88 The badge text for the 'Escalation Metrics' EntityCard is hardcoded as 'status', which is vague and uninformative. It does not convey meaningful information about the metrics or escalation state, reducing UI clarity and potentially confusing users. ScalarCreatePreview loses label association for slider input📍 ui/ts/components/ScalarCreatePreview.tsx:29 The parent element wrapping the range input was changed from a label to a div, removing the implicit association between the 'Scalar Preview' text and the input. This breaks accessibility for screen reader users who rely on proper labeling of form controls. Min and Max value statistics omitted from ScalarCreatePreview📍 ui/ts/components/ScalarCreatePreview.tsx:45 The refactored component removed the Min Value and Max Value displays from the statistics grid. Users no longer see the lower and upper bounds of the scalar range, which are essential for understanding the market parameters. This may lead to confusion or incorrect market creations. Incorrect button label precedence when both duplicate pool and Zoltar fork conditions are true📍 ui/ts/components/SecurityPoolSection.tsx:51 The create button label logic checks 'duplicateOriginPoolExists' before 'zoltarUniverseHasForked'. When both conditions are true (i.e., a pool with the same details already exists and the universe has forked), the label incorrectly shows 'Pool Already Exists' instead of the more fundamental 'Pool Creation Locked'. This misleads the user about the actual reason pool creation is disabled. Crash when selectedPool.marketDetails is undefined due to unguarded getQuestionTitle call📍 ui/ts/components/SecurityPoolWorkflowSection.tsx:63 The selectedPoolTitle computation calls getQuestionTitle(selectedPool.marketDetails) without verifying that selectedPool.marketDetails exists. If a pool is selected but its marketDetails property is undefined (e.g., metadata failed to load or is still loading), this will throw a runtime error and crash the component. The rest of the component safely uses a fallback marketDetails variable that aggregates from selectedPool, reporting, and forkAuction sources, but the title does not use this safe variable. The title should either use the same fallback marketDetails or include a guard to avoid passing undefined to getQuestionTitle. Inconsistent showHeader prop handling in SecurityPoolsSection📍 ui/ts/components/SecurityPoolsSection.tsx:33 The showHeader={false} prop was removed from SecurityPoolsOverviewSection in the 'browse' view, while it remains explicitly set to false for 'create' and 'operate' views. This inconsistency likely causes the 'browse' view to display an unintended header from SecurityPoolsOverviewSection, violating the consistent header-hidden design across all sub-views and resulting in incorrect UI behavior. Approve button label and tooltip crash when REP allowance is undefined📍 ui/ts/components/SecurityVaultSection.tsx:63 When the REP allowance (securityVaultRepAllowance) is undefined (e.g., still loading) and the user enters a positive deposit amount, both approveButtonLabel and approveButtonTitle attempt to format approvalShortage (which is undefined) using formatCurrencyBalance, causing a runtime TypeError that crashes the component. The label expression should handle undefined approvalShortage, and the tooltip function should guard against undefined before formatting. Add a check for approvalShortage === undefined and display an appropriate message (e.g., 'Loading Approval...') while avoiding formatCurrencyBalance calls with undefined. Withdraw amount input lacks validation and balance check📍 ui/ts/components/SecurityVaultSection.tsx:39 The REP withdraw amount field is not parsed using parseRepAmountInput, so invalid inputs (negative, non-numeric, decimals) are accepted. Additionally, the withdraw button's disabled condition does not verify that the entered amount is positive and does not exceed the available withdrawable balance (withdrawableRepAmount). This permits submitting transactions that will fail. To fix, parse repWithdrawAmount into a bigint, define hasWithdrawAmount = parsed > 0n, and define hasSufficientWithdrawableAmount = hasWithdrawAmount && withdrawableRepAmount !== undefined && parsed <= withdrawableRepAmount. Then update the withdraw button's disabled condition to use hasSufficientWithdrawableAmount. Also remove the old hasWithdrawAmount definition that only checked for non-empty string. Deposit button does not validate against available REP balance📍 ui/ts/components/SecurityVaultSection.tsx:60 The deposit button disabled condition only checks for sufficient allowance (approved REP) but does not ensure the deposit amount does not exceed the user's current REP balance (securityVaultRepBalance). This can lead to deposit transactions failing due to insufficient token balance. To fix, introduce a constant hasSufficientDepositBalance = depositAmount !== undefined && securityVaultRepBalance !== undefined && depositAmount <= securityVaultRepBalance, and include it in the disabled condition of the deposit button. Missing fallback for unknown vault action type in Latest Vault Action display📍 ui/ts/components/SecurityVaultSection.tsx:82 The latestActionLabel mapping uses an object lookup without a default case. If securityVaultResult.action contains a value not present in the mapping, the lookup returns undefined and the UI renders 'Action: undefined'. This is incorrect. The lookup should provide a fallback using the raw action string, e.g., change line 82 from '}[securityVaultResult.action]' to '}[securityVaultResult.action] ?? securityVaultResult.action'. Incorrect 'fully split' message when split limit is zero📍 ui/ts/components/ZoltarMigrationSection.tsx:133 When the migration outcome split limit is zero and outcome indexes are selected, the hint messages incorrectly state that the amount is already fully split across the selected universes. In reality, a split limit of zero means no REP can be allocated to the selected outcomes, so the REP remains in the migration balance and cannot be split. This misleads users into believing the migration is complete, potentially causing them to forgo necessary actions and resulting in failed migrations. The issue affects both the prepare button hint (via getAlreadyPreparedHint) and the split button hint (splitHintMessage). Incorrect BigInt conversion in loadOpenOracleReportDetails causing TypeErrorThe loadOpenOracleReportDetails function incorrectly wraps values that are already bigints (as returned by readContract for uint256 fields) with BigInt(). This causes a runtime TypeError, preventing the function from executing successfully. Affected fields: settlementTime, feePercentage, protocolFee, multiplier, disputeDelay, reportTimestamp, settlementTimestamp, and numReports. Incorrect repDepositShare calculation in loadSecurityVaultDetailsloadSecurityVaultDetails incorrectly treats the first element of vaultData (poolOwnership) as repDepositShare without converting it. The correct approach is to use poolOwnershipToRep to obtain the repDepositShare, as done in loadSecurityPoolVaultSummaries. This leads to wrong repDepositShare values in the result. Incorrect update of augurPlaceHolderDeployed in setDeploymentStatuses📍 ui/ts/hooks/useOnchainState.ts:74 The setDeploymentStatuses function sets augurPlaceHolderDeployed.value to true when all deployment steps are deployed, but augurPlaceHolderDeployed should reflect the on-chain deployment status from the snapshot (set in refreshState). Deriving it from local deployment statuses can cause it to be out of sync with the actual on-chain state, leading to incorrect UI or behavior that depends on this flag. loadOracleReport does not set amount2 from report details📍 ui/ts/hooks/useOpenOracleOperations.ts:68 The loadOracleReport function updates the form's amount1 and stateHash but fails to set amount2 with the token2 amount from the report (e.g., details.exactToken2Report). As a result, after loading a report, the form's amount2 remains empty or stale, causing approveToken2 to fail when parsing the amount. This breaks the ability to approve token2 after loading a report. Promise.all causes price fetch to fail entirely when USDC price request fails📍 ui/ts/hooks/useRepPrices.ts:41 The useRepPrices hook fetches REP/ETH and REP/USDC prices in parallel using Promise.all. If quoteRepForUsdcV4 (or quoteRepForEth with its fallback) rejects, the entire Promise.all rejects, triggering the catch block which leaves all prices undefined. This means a successful ETH price is discarded simply because the USDC fetch failed. The intended behavior is to set each price independently; a failure in one should not prevent the other from being set. The fix is to use Promise.allSettled or separate error handling for each fetch so that partial success is preserved. Incorrect order of pre-creation checks: deployment check before fork check📍 ui/ts/hooks/useSecurityPoolCreation.ts:121 The createPool function checks for the deployment of SecurityPoolFactory before checking if the universe has forked. When both conditions are false, the user receives the deployment error instead of the fork error, which is misleading because the fork is an absolute barrier regardless of deployment status. The fork check should be performed first. resetSecurityPoolCreation does not clear poolCreationMarketDetails📍 ui/ts/hooks/useSecurityPoolCreation.ts:171 The resetSecurityPoolCreation function only resets securityPoolError and securityPoolResult, leaving poolCreationMarketDetails set. This can cause stale market details from a previous creation to persist after reset, leading to incorrect UI state. Type mismatch in market details reuse condition always forces reload📍 ui/ts/hooks/useSecurityPoolCreation.ts:140 The condition REP balance not refreshed after depositRep📍 ui/ts/hooks/useSecurityVaultOperations.ts:141 After a successful deposit of REP into the security pool, the securityVaultRepBalance signal is not updated. The UI will continue to display the old balance, potentially confusing users about available funds. REP balance not refreshed after withdrawRep📍 ui/ts/hooks/useSecurityVaultOperations.ts:195 After withdrawing REP from the security pool, the securityVaultRepBalance signal is not updated. The displayed balance will remain stale until a manual refresh. Stale vault details after account change📍 ui/ts/hooks/useSecurityVaultOperations.ts:199 When the connected wallet account changes, the hook retains the previous account's securityVaultDetails, securityVaultError, securityVaultForm, and securityVaultResult. This leads to inconsistent UI state where old vault data is shown alongside the new balance/allowance. The hook should reset vault-specific state upon accountAddress changes. Silent failure in initial data loading due to unhandled promise rejections📍 ui/ts/hooks/useZoltarUniverse.ts:175 The auto-load effect uses Promise.allSettled to call loadZoltarUniverse and loadZoltarQuestionCountData but ignores the results. Both functions can throw errors (e.g., network failures, contract reverts), and these errors are silently discarded. No error state is updated to inform the user, leading to a situation where loading completes with no data and no indication of failure. Off-by-one error in effectiveDecimals calculation for two significant figuresThe formula Validation does not enforce endTime > startTime when startTime is empty (defaults to 0n)📍 ui/ts/lib/marketCreation.ts:145 createQuestionData defaults startTime to 0n when the input is empty. validateMarketForm only compares endTime and startTime when both fields are provided (parsed). If startTime is empty and endTime is provided but less than or equal to 0 (e.g., '0'), the validation passes because the relational check is skipped. However, createQuestionData then throws 'End time must be after start time' because endTime (0n) <= startTime (0n). This results in an unhandled exception after the form was validated successfully, breaking the submission flow. parseBigIntInput accepts negative numbersThe parseBigIntInput function currently accepts negative numbers by using BigInt(trimmed) without checking for a leading minus sign. Since this function is likely used for parsing non-negative integer inputs (amounts, indexes, etc.), accepting negative values leads to invalid data that could cause transaction failures or incorrect state. The function should reject negative numbers explicitly. parseRepAmountInput accepts '.' as valid input (should be invalid)The parseRepAmountInput function normalizes inputs that start or end with a decimal point. However, a single dot '.' becomes '0.' after normalization, which parseUnits accepts as zero. This incorrectly treats an incomplete input as a valid zero, potentially leading to unintended zero-valued transactions. A single dot should be rejected as invalid. normalizeDecimalInput does not handle negative numbers with leading decimal point📍 ui/ts/lib/scalarOutcome.ts:21 The function normalizeDecimalInput normalizes positive numbers starting with '.' (e.g., '.5' -> '0.5') but does not handle negative numbers starting with '-.' (e.g., '-.5'). This leads to parseUnits receiving an invalid string and throwing 'must be a decimal number', rejecting valid user input. The function should also convert '-.5' to '-0.5'. getScalarSliderFillWidth lacks input validation📍 ui/ts/lib/scalarOutcome.ts:66 The exported function getScalarSliderFillWidth does not validate its parameters, unlike similar utilities (getScalarSliderProgress, clampScalarTickIndex). Invalid arguments (numTicks <= 0, tickIndex out of range) produce invalid CSS values (e.g., 'calc(Infinity% - Infinity rem + 0.5rem)') or incorrect visual output, potentially breaking the UI. The function should include the same validation as other slider-related functions. parseScalarFormInputs incorrectly rejects valid two-tick configurations📍 ui/ts/lib/scalarOutcome.ts:92 The validation condition Misplaced test suites: getMigrationOutcomeSplitLimit tests nested under wrong describe block📍 ui/ts/tests/migrationOutcomeUniversesSection.test.ts:36 The two new tests for getMigrationOutcomeSplitLimit are incorrectly placed inside the describe block for getMigrationOutcomeHeldBalance. This misorganization can lead to confusion in test reporting and violates the principle of grouping tests by the unit under test. They should be moved into their own describe('getMigrationOutcomeSplitLimit') block. Missing fee and tickSpacing parameters in quoteExactInput call📍 ui/ts/tests/uniswapQuoter.integration.test.ts:68 In the test for REP/USDC with no V4 pool (line 68), quoteExactInput is called without the required fee and tickSpacing parameters. All other calls to quoteExactInput in this file include these parameters, indicating they are necessary. Omitting them may cause the function to throw due to invalid arguments rather than the absence of a pool, leading to a false positive where the test passes for the wrong reason. Inistent naming between form field and queued operation in OpenOracleFormStateIn OpenOracleFormState, the form field 'securityBondAllowanceAmount' uses singular 'Bond', while the queued operation 'setSecurityBondsAllowance' uses plural 'Bonds'. This inconsistency could lead to bugs in code that maps operation names to form fields, causing undefined values or incorrect behavior, especially if dynamic key lookup or string matching is used. |
🏛️ Architect36 issues found Hardcoded line-specific source code modifications in configuration file📍 .claude/settings.local.json:23 The settings.local.json configuration file now includes Bash(sed) commands that modify specific line numbers (57 and 65) in SecurityPoolsOverviewSection.tsx. This violates key architectural principles: configuration should be declarative and environment-specific, not contain imperative code transformation logic; hardcoding line numbers creates brittle coupling to file structure; this approach bypasses proper refactoring workflows and version control; and it mixes abstraction levels by embedding implementation details in configuration. Such patterns lead to significant maintenance debt and should be replaced with proper codemod scripts or manual code reviews. Local timestamp state causes potential desynchronization with Anvil node📍 solidity/ts/testsuite/simulator/AnvilWindowEthereum.ts:81 The refactoring introduced local variables 'currentTimestamp' and 'snapshotTimestamp' to cache the blockchain timestamp. However, the 'request' method allows arbitrary RPC calls, including those that modify time (e.g., 'evm_increaseTime', 'evm_setNextBlockTimestamp', 'evm_mine'), bypassing the local state updates. This can lead to 'getTime' and 'getBlock' returning stale values, making tests unreliable. Additionally, snapshot and revert operations rely on this local state, which may not match the node's state after external time changes, violating the mock's purpose as a faithful proxy. Inefficient global refresh of file watchersThe refreshTypeScriptWatchers functions (and the directory watchers that trigger them) clear and recreate all file and directory watchers whenever any single file or directory change is detected. This O(n) operation on each change is an anti-pattern that does not scale with project size and can cause high CPU and I/O. Instead, the watcher set should be updated incrementally: add watchers for newly created files/directories and remove watchers for deleted ones. Removal of TypeScript compiler state awareness introduces reload race conditionsPreviously, live reload was only triggered upon detecting 'Found 0 errors' in the TypeScript compiler output, guaranteeing a successful compilation before reload. The new approach relies solely on filesystem events for both source and output files, which can trigger reloads before the compiler finishes writing files or on partial/broken builds. This leads to inconsistent browser state and potentially two reloads per change. This is a regression in reliability and an architectural regression from event-driven to filesystem-driven change detection without proper synchronization. Incomplete adoption of new CSS design tokensThe diff introduces new CSS custom properties --notice-error-gradient and --danger-text intended for error notice styling but fails to update the .notice.error component to use them. The .notice.error rule continues to use hardcoded gradient and color values, leading to inconsistency, violating DRY principles, and risking visual discrepancies when design tokens evolve. God Component Anti-Pattern in App.tsxThe App component violates the Single Responsibility Principle by orchestrating at least 9 distinct business domains (deployment flow, market creation, security pools, vault operations, oracle operations, reporting, trading, fork auctions, REP prices). It combines routing logic, global transaction state management, wallet connection state, and UI composition for all sections. This creates high coupling between unrelated concerns, makes testing nearly impossible, and will severely hinder future scalability and maintenance. Any change to one domain risks breaking others due to the monolithic structure. Inconsistent Hook Abstraction BoundariesThe codebase shows an inconsistent pattern for hook configuration: most hooks accept a baseHookConfig object, but useMarketCreation and useSecurityPoolCreation require additional domain-specific parameters (activeUniverseId, deploymentStatuses, zoltarUniverseHasForked), while useRepPrices accepts no configuration at all. This violates the Interface Segregation Principle and creates unclear architectural boundaries. The baseHookConfig appears intended as a contract for infrastructure concerns (transactions, refresh), but its application is irregular, suggesting the abstraction was not systematically designed. Breaking change in exported utility function contract📍 ui/ts/components/MigrationOutcomeUniversesSection.tsx:15 The function Component violates Single Responsibility Principle by aggregating multiple independent workflows📍 ui/ts/components/OpenOracleSection.tsx:19 OpenOracleSection combines seven distinct responsibilities: displaying report details, oracle manager details, latest oracle action, browsing oracle games, submitting initial reports, disputing reports, and managing oracle manager operations. This high coupling between unrelated features makes the component large (300+ lines), hard to test, and difficult to extend. Each workflow should be extracted into its own focused component with dedicated state and handlers. Shared form state couples independent workflows, creating implicit dependencies📍 ui/ts/components/OpenOracleSection.tsx:189 The OpenOracleFormState object aggregates input fields from four independent workflows (browse, report submission, dispute, manager operations). This implicit coupling leads to complex validation logic, unnecessary re-renders when unrelated fields change, and high risk of regressions when extending the form. The state should be decomposed per workflow to enforce separation of concerns and improve maintainability. Single Responsibility Principle Violation - Component Handles Two Distinct Workflows📍 ui/ts/components/SecurityPoolSection.tsx:70 The SecurityPoolSection component conditionally renders completely separate UI flows: a pool creation form workflow (lines 104-196) and a pool creation result display workflow (lines 70-103). These workflows have different structures, purposes, and user interactions. This violates the Single Responsibility Principle, making the component complex, hard to test, and brittle to change. Any modification risks affecting both workflows unintentionally. Code Duplication - Question Display and Loading Logic Repeated Across Branches📍 ui/ts/components/SecurityPoolSection.tsx:72 The 'Question' EntityCard component with its associated 'Load Question' button is duplicated in both the result view (lines 72-82) and form view (lines 108-129). This violates the DRY (Don't Repeat Yourself) principle, creating a maintenance burden where any visual or behavioral change must be applied in two locations, increasing risk of inconsistency and bugs. Incorrect data source mixing in marketDetails variable📍 ui/ts/components/SecurityPoolWorkflowSection.tsx:56 marketDetails is defined as Missing guard for selectedPool.marketDetails in selectedPoolTitle📍 ui/ts/components/SecurityPoolWorkflowSection.tsx:63 selectedPoolTitle unconditionally calls Utility function exported from component file violates separation of concerns📍 ui/ts/components/SecurityPoolsOverviewSection.tsx:6 The function Business Logic Mixed with UI Presentation Layer📍 ui/ts/components/SecurityVaultSection.tsx:33 The component contains extensive business logic including form normalization, currency parsing with error handling, approval calculations, fee eligibility checks, and conditional enable/disable logic embedded directly in the UI component. This violates separation of concerns principles and makes the component responsible for both presentation and business rules. Lines 33-96 demonstrate calculations that should be extracted to a custom hook or business logic layer. The component also decides when to perform side effects (auto-load vault) based on business rules rather than delegating to a controller or container component. High Coupling to Specific Implementation Details📍 ui/ts/components/SecurityVaultSection.tsx:6 The component is tightly coupled to specific implementations of parsing functions (parseRepAmountInput), formatting functions (formatCurrencyBalance), and network checks (isMainnetChain). It also has intimate knowledge of the structure of securityVaultDetails and securityVaultForm objects, including nested property access and specific field semantics. This makes the component difficult to test in isolation and impossible to reuse with different implementations or data sources. Side Effects in Render Path via useEffect with Complex Dependencies📍 ui/ts/components/SecurityVaultSection.tsx:83 The useEffect at lines 87-96 performs an auto-load action but depends on 9 different dependencies including derived values like autoLoadKey and normalizedSecurityVaultForm.securityPoolAddress. The dependency array includes values that change frequently, potentially causing unintended re-runs of the effect. The guard conditions inside the effect suggest the logic belongs in a state management layer rather than a UI component. The use of a ref to prevent duplicate loads is a code smell indicating procedural thinking in a declarative framework. Redundant derived state and inconsistent updates for augurPlaceHolderDeployed📍 ui/ts/hooks/useOnchainState.ts:71 The signal Single Responsibility Principle violation in useOpenOracleOperations hook📍 ui/ts/hooks/useOpenOracleOperations.ts:22 The hook is responsible for an excessive number of distinct concerns: loading oracle manager and report details, managing form state, approving tokens, requesting prices, queuing operations, submitting/settling/disputing reports. This violates the Single Responsibility Principle, leading to high complexity, poor testability, and difficult maintenance. It should be decomposed into smaller, focused units (e.g., separate hooks or services for data loading and actions). Tight coupling to blockchain contract layer📍 ui/ts/hooks/useOpenOracleOperations.ts:3 The hook directly imports and invokes contract interaction functions (e.g., loadOracleManagerDetails, approveErc20), creating a hard dependency on the blockchain implementation. This breaks separation of concerns and the dependency inversion principle, making the UI layer difficult to test in isolation and vulnerable to changes in contract interfaces. An abstraction layer (e.g., a service or use-case interactor) should be introduced to decouple UI from contracts. Inconsistent data access with runtime type checks📍 ui/ts/hooks/useOpenOracleOperations.ts:120 The code uses runtime type checks like Inconsistent memoization of callback functions in useZoltarFork hook📍 ui/ts/hooks/useZoltarFork.ts:114 The hook defines runZoltarForkAction as a non-memoized function, causing it to be recreated on every render. approveZoltarForkRep is wrapped in useCallback with runZoltarForkAction as a dependency, but since runZoltarForkAction changes on every render, approveZoltarForkRep also changes on every render, making useCallback ineffective. Additionally, this can lead to stale closures if runZoltarForkAction depends on changing props, as approveZoltarForkRep may hold a reference to an outdated runZoltarForkAction. forkZoltar is not memoized at all, creating inconsistency. This violates the React/Preact pattern of stable function references and can cause unnecessary re-renders and functional bugs when these functions are passed to child components or used in dependency arrays. Inconsistent validation strategy with duplicated logic📍 ui/ts/lib/marketCreation.ts:56 The file implements two competing validation approaches: createQuestionData uses exception throwing for title and time order validation, while the new validateMarketForm collects errors into a structured result. The validation for 'title required' and 'endTime > startTime' is duplicated (lines 56-57 vs lines 112-115 and 145-149). This creates architectural inconsistency, making it unclear which function should be used and risking divergent rules when changes are made, as both locations must be kept in sync. Single Responsibility Principle violation: marketCreation.ts mixes multiple concerns📍 ui/ts/lib/marketCreation.ts:1 The marketCreation.ts module has grown to include market parameter creation, form validation, parsing helpers, utilities, and cryptographic functions. The new validateMarketForm function alone exceeds 100 lines. This bloat violates SRP, making the module difficult to test, understand, and maintain. Changes to validation, parsing, or market creation all affect the same file, increasing coupling and risk of regressions. Fragile error message parsing in scalar validation📍 ui/ts/lib/marketCreation.ts:182 validateMarketForm (lines 186-197) determines which fields to flag as invalid by parsing the text of error messages from parseScalarFormInputs using string checks (e.g., message.includes('Scalar increment')). This tightly couples validation to the exact wording of error messages, making the code brittle. Any change to those messages in parseScalarFormInputs will break field error mapping, potentially causing incorrect UI feedback or silent failures. Single module violates Single Responsibility Principle by containing multiple unrelated form state factoriesThe file Hardcoded Network and Token Configuration📍 ui/ts/lib/uniswapQuoter.ts:4 Contract addresses (UNISWAP_V4_QUOTER_ADDRESS, UNISWAP_V3_QUOTER_ADDRESS), token addresses (REP_ADDRESS, USDC_ADDRESS), and pool parameters (DEFAULT_POOL_CONFIG, REP_USDC_V4_POOL) are hardcoded directly in the module. This prevents reuse across different networks or environments, forces code changes for configuration updates, and tightly couples the implementation to specific deployments. These values should be externalized (e.g., via environment variables, configuration files, or dependency injection) to adhere to the principle of separating configuration from code. Mixing Infrastructure Logic with Domain-Specific Tokens and Business Rules📍 ui/ts/lib/uniswapQuoter.ts:9 The module combines generic Uniswap infrastructure (ABI definitions, viem client calls) with application-specific domain knowledge: hardcoded token addresses (REP_ADDRESS, USDC_ADDRESS) and convenience functions that exclusively support those tokens (quoteRepForEth, quoteEthForRep, quoteRepForEthV3, quoteRepForUsdcV4). This violates layered architecture and the Single Responsibility Principle. Infrastructure should be independent of domain decisions. The current design forces business logic changes (e.g., adding a new token) to modify infrastructure code, hindering testability, reuse, and maintainability. Exporting Internal Implementation Constants Breaks Encapsulation📍 ui/ts/lib/uniswapQuoter.ts:4 The module exports UNISWAP_V4_QUOTER_ADDRESS, an internal implementation detail about which contract implements the quoting logic. This exposes infrastructure specifics to consumers, creating a brittle dependency. If the address changes (e.g., due to an upgrade), all importing modules break. Only the functional API needed by consumers should be exported; internal constants like contract addresses should remain private or be provided via an abstracted configuration interface. Breaking change: onApproveZoltarForkRep callback signature modified📍 ui/ts/types/components.ts:83 The onApproveZoltarForkRep prop type in MarketRouteContentProps changed from () => void to (amount?: bigint) => void. This is a breaking change: any component implementing this callback without an optional bigint parameter will fail TypeScript's type checking and may cause runtime errors if the argument is passed. All consumers of MarketRouteContentProps must be updated. Breaking change: onApproveRep callback signature modified📍 ui/ts/types/components.ts:206 The onApproveRep prop type in SecurityVaultRouteContentProps changed from () => void to (amount?: bigint) => void. This breaks any existing implementation that does not accept an optional bigint argument, causing type errors and potential runtime failures. This requires updating all components that pass this callback. Breaking change: Removal of onRedeemRep and onUpdateVaultFees from SecurityVaultRouteContentPropsSecurityVaultRouteContentProps no longer includes onRedeemRep and onUpdateVaultFees callbacks. These were replaced with onSetSecurityBondAllowance and onWithdrawRep, but the semantics have changed. Any component that previously relied on these callbacks will encounter undefined values and runtime errors when attempting to call them. This is a breaking change that requires refactoring dependent components to use the new callbacks, if equivalent functionality still exists. Breaking change: Removal of lastCreatedQuestionId and onLoadLatestMarket from SecurityPoolRouteContentPropsSecurityPoolRouteContentProps removed lastCreatedQuestionId (string | undefined) and onLoadLatestMarket (() => void). Components that read lastCreatedQuestionId or call onLoadLatestMarket will break. The removal of these properties reduces the interface's functionality and may require redesign of related components that depend on them. Breaking change: Removal of showHeader from SecurityPoolsOverviewSectionPropsSecurityPoolsOverviewSectionProps was simplified by removing the optional showHeader boolean property that previously allowed controlling header visibility. Any component using this prop will either pass an extraneous prop (React warnings) or, if TypeScript strict checking is enabled, fail to compile. More importantly, the component's behavior might change if it relied on showHeader to conditionally render elements. Inconsistent naming for state hash fields across oracle-related types📍 ui/ts/types/contracts.ts:140 The types 'OracleManagerDetails' and 'OpenOracleReportDetails' define fields for state hashes with inconsistent names: 'callbackStateHash' in OracleManagerDetails and 'stateHash' in OpenOracleReportDetails. This naming inconsistency can lead to confusion and errors when these types are used interchangeably or when developers assume they represent the same concept. Given the critical nature of state hashes in blockchain applications, such inconsistencies increase the risk of bugs and undermine code clarity. |
🔧 Expensive Linter24 issues found Incorrect markdown list item formatting in Notes sectionThe Notes section at the end of AGENTS.md uses a double hyphen prefix ('- -') for list items instead of the standard single hyphen ('-') used throughout the rest of the file. This creates inconsistent markdown formatting and will render as nested list items or plain text depending on the parser. CSS variable --slider-thumb-border placed in incorrect thematic groupThe variable --slider-thumb-border is added in the :root block between the '/* decorative /' group and the new '/ notice error /' group, but it logically pertains to form controls and should be grouped with other control-related variables (e.g., --control-bg, --control-border) under the '/ controls */' section. All variables in the codebase are organized under clear thematic headers, and this variable's placement breaks that convention, reducing maintainability. Inconsistent container element for categorical outcomes field📍 ui/ts/components/MarketCreateQuestionSection.tsx:151 The categorical outcomes field uses a element with className='field', while all other form fields use a element with the same className. This breaks consistency in the HTML structure for form controls, even though the
may be necessary due to the inclusion of a button element. The prevailing style in the codebase uses for all other field containers, so this deviation is a stylistic inconsistency.
Inconsistent handling of non-existing child universes in held balance display📍 ui/ts/components/MigrationOutcomeUniversesSection.tsx:54 The function getMigrationOutcomeHeldBalance now returns 0n for non-existing child universes, but the UI always renders a CurrencyValue component showing 0 REP instead of conditionally rendering a 'Not deployed yet' message as in the original code. This leads to a confusing user experience where a non-existent universe displays a zero balance rather than indicating it is not deployed.Although this has functional implications, the inconsistency in UI representation based on the same data (child.exists) versus the balance value constitutes a stylistic and logical deviation from the original conditional rendering approach. CSS variable usage in inline style inconsistent with repository patterns📍 ui/ts/components/ScalarDeploymentSection.tsx:69 The new code introduces a CSS custom property '--slider-fill' in an inline style (line 69). Based on the existing codebase, which uses direct inline styles (e.g., original width style), this represents a stylistic shift without clear precedent. The repository appears to avoid CSS variables in inline styles, favoring direct property assignments for dynamic values. Class name removal breaks consistent styling pattern📍 ui/ts/components/ScalarDeploymentSection.tsx:99 The class 'market-scalar-deploy-grid' was removed from the grid container (line 99). This class appears to be part of a naming convention for scalar deployment sections, and its removal may cause styling inconsistencies with other similar components that rely on this class for layout. Import ordering does not follow repository conventions📍 ui/ts/components/ScalarDeploymentSection.tsx:1 Imports are not grouped by type (value vs. type) or source. Value imports from 'preact/hooks' are split (lines 1 and 5), and type imports are interleaved with value imports (lines 2 and 8). The repository likely follows a standard grouping: standard library, third-party, local, with type imports grouped separately. Prop destructuring order not alphabetical for newly added onResetSecurityPoolCreation📍 ui/ts/components/SecurityPoolSection.tsx:20 The newly added prop Destructured parameter order: optional parameters placed before required ones📍 ui/ts/components/SecurityVaultSection.tsx:11 The function signature for SecurityVaultSection interleaves optional parameters (compactLayout, autoLoadVault) before several required ones, breaking the pattern established in the existing codebase where all required parameters are listed first followed by optional ones. This reduces readability and consistency. Move compactLayout and autoLoadVault after all required parameters. Local component imports not sorted alphabetically📍 ui/ts/components/TradingSection.tsx:1 The imports from './' are not sorted alphabetically. 'EntityCard' should be imported before 'EnumDropdown' as 'Entity' comes before 'Enum' alphabetically. Callback prop
|
🧠 Wise Man37 issues found Typographical formatting error in documentation bullet pointsIn the 'Notes' section of AGENTS.md, each bullet point incorrectly begins with '- - ' instead of the proper markdown list format '- '. This introduces an unwanted dash in the rendered content, impairing readability and creating an unprofessional appearance. Incorrect snapshot timestamp management for multiple or failed snapshots📍 solidity/ts/testsuite/simulator/AnvilWindowEthereum.ts:81 The mock tracks only a single Internal timestamp state may diverge from Anvil when using raw RPC calls📍 solidity/ts/testsuite/simulator/AnvilWindowEthereum.ts:58 The mock maintains Brittle error handling in manipulateTime using error message text📍 solidity/ts/testsuite/simulator/AnvilWindowEthereum.ts:212 The SetTimestamp branch of Fragile error handling in validateLocalhostUrl based on error message content📍 solidity/ts/testsuite/simulator/AnvilWindowEthereum.ts:85 The function catches any error from Excessive code duplication in TypeScript watcher functionsThe functions Missing error handling for file system watchersThe Missing walletBootstrapComplete guard in route content disabled conditionThe isRouteContentDisabled variable previously included a check for !walletBootstrapComplete, ensuring the UI was disabled before the wallet was initialized. This check was removed, allowing user interaction with forms and buttons before the wallet is ready, which can lead to transaction failures, confusing errors, and a poor user experience. The condition should be restored to maintain defensive UI gating. StepStatus.label type is overly permissive📍 ui/ts/components/DeploymentSection.tsx:4 The Unnecessary arrow function wrapper in onClick handler📍 ui/ts/components/ForkZoltarSection.tsx:105 The approve button's onClick handler is unnecessarily wrapped in an arrow function that calls the prop without arguments. This creates a new function on every render, causing unnecessary re-renders for any memoized child components and breaking referential equality. The direct function reference Prop type includes unused optional parameter📍 ui/ts/components/ForkZoltarSection.tsx:14 The prop Missing validation feedback for answerUnit field📍 ui/ts/components/MarketCreateQuestionSection.tsx:178 The scalar 'Answer Unit' input does not receive the 'invalid' prop based on validation state, unlike other scalar fields (scalarMin, scalarIncrement, scalarMax). This creates an inconsistent user experience where some fields show validation errors visually while others do not, even if the validation logic includes errors for answerUnit. Removal of state-specific CSS class reduces styling granularity📍 ui/ts/components/MarketOverviewSection.tsx:44 The change removes the 'market-overview-loading' class from the loading state paragraph, which previously allowed targeted styling for the loading condition. This reduces CSS specificity and may require more fragile selectors to style loading states differently, potentially leading to higher maintenance overhead and unintended style leakage into other 'detail' paragraphs. Incorrect remaining capacity calculation in getMigrationOutcomeSplitLimit📍 ui/ts/components/MigrationOutcomeUniversesSection.tsx:28 The function uses Duplicate zero address magic string📍 ui/ts/components/OpenOracleSection.tsx:76 The zero address constant '0x0000000000000000000000000000000000000000' is duplicated in two conditional checks (lines 76 and 130). This violates DRY principles and creates maintainability risk if the value ever needs to change. Extract this into a module-level constant named Component exceeds maintainable complexity📍 ui/ts/components/OpenOracleSection.tsx OpenOracleSection has grown to over 300 lines and handles rendering of multiple unrelated sections (Report Details, Oracle Manager, Latest Action, Browse, Submit Report, Dispute, Zoltar). This violates Single Responsibility Principle, increases cognitive load, and makes the component hard to test or modify. Extract each logical section into its own focused component (e.g., ReportDetailsCard, OracleManagerCard, BrowseReportForm, SubmitReportForm, DisputeForm, ZoltarForm) either in the same file or separate files. This will improve readability, enable isolated testing, and simplify future changes. Range input missing associated label📍 ui/ts/components/ScalarCreatePreview.tsx:30 The range input element lacks an associated label, which is essential for accessibility. The 'Scalar Preview' text should be wrapped in a element or linked via htmlFor and id attributes to ensure screen reader users understand the input's purpose. This regression occurred when the structure changed from a wrapper to a .
Duplicated conditional logic for invalid state display📍 ui/ts/components/ScalarCreatePreview.tsx The condition Component mixes distinct UI responsibilities; should be split into smaller components📍 ui/ts/components/SecurityPoolSection.tsx SecurityPoolSection currently handles two very different user flows: pool creation (form, validation, loading states) and post-creation display (result details and reset). This violates the Single Responsibility Principle, resulting in a large (~200 lines) component with complex conditional rendering. The component becomes harder to read, test, and maintain because changes to one flow may inadvertently affect the other. Additionally, similar UI elements (e.g., the Question card) are used in both states but with slight variations, increasing cognitive load. Extract two focused components: SecurityPoolCreator (handling the creation form, its validation, and related UI) and SecurityPoolResult (displaying deployment details and providing a reset action). This will simplify the main component to a straightforward conditional render, improve clarity, and align with long‑term maintainability best practices. Nested ternary operator reduces code readability📍 ui/ts/components/SecurityPoolWorkflowSection.tsx:63 The selectedPoolTitle assignment uses a nested ternary which is hard to read and maintain. Consider using an IIFE or if-else statements for clarity, as nested ternions increase cognitive load and are prone to errors during modification. Duplication of vault details metrics and actions📍 ui/ts/components/SecurityVaultSection.tsx:105 The JSX for rendering vault metrics (REP Deposit Share, Approved REP, Security Bond Allowance, Unpaid ETH Fees, Locked REP, Total Security Bond Allowance) and the Claim Fees button is duplicated in two places: within the TradingSection component violates Single Responsibility Principle📍 ui/ts/components/TradingSection.tsx:9 TradingSection combines multiple distinct concerns: rendering a header, displaying the latest trading result, managing a multi-field trading form, showing errors, and controlling UI visibility flags. This is evidenced by its 11 props and monolithic JSX structure (over 90 lines). A component with such broad responsibilities becomes hard to test, understand, and maintain. Consider extracting focused subcomponents like TradingHeader, TradingResultCard, and TradingFormCard, and introduce a thin container to orchestrate them. This decomposition aligns with SRP, improves readability, and reduces cognitive load. Dead code in prepareHintMessage: unreachable hasSufficientAllowance check📍 ui/ts/components/ZoltarMigrationSection.tsx:150 The conditional block Redundant async/await in loadAllZoltarQuestionsThe function uses an unnecessary async callback with await inside the map, and also awaits the Promise.all result. Since Promise.all already returns a promise that resolves to an array of results, we can simplify by removing the async keyword and inner await from the map callback, and remove the outer await. This reduces microtask overhead and improves readability. Unnecessary 'return await' in async functionsMany async functions directly return the result of awaiting another async operation using 'return await'. Since the enclosing function is already async, returning the promise directly (without 'await') is sufficient and avoids an extra microtask, improving performance and preserving stack traces. This pattern appears in numerous wrapper functions and should be removed. Multiple sources of truth for augurPlaceHolderDeployed state📍 ui/ts/hooks/useOnchainState.ts:71 The augurPlaceHolderDeployed signal is assigned in two different locations: within setDeploymentStatuses (lines 71–75) and in the loadDeploymentStatusOracleSnapshot promise resolution (line 89). This violates the single source of truth principle, making state changes harder to reason about and increasing the risk of inconsistencies. Derive this value from a single authoritative source (e.g., blockchain snapshot) or centralize updates in one place to improve maintainability. Duplicated manager details fetching logic in requestPrice and queueOperation📍 ui/ts/hooks/useOpenOracleOperations.ts:138 The logic for obtaining OracleManagerDetails (either from the cached signal or by fetching from the contract) is duplicated in the Incomplete state reset in resetSecurityPoolCreation📍 ui/ts/hooks/useSecurityPoolCreation.ts:171 The resetSecurityPoolCreation function does not reset poolCreationMarketDetails, leaving stale state after reset. This is inconsistent with the reset logic in createPool, which clears poolCreationMarketDetails before starting a new creation. For a clean reset, all creation-related signals should be cleared to avoid displaying outdated information. useCallback with unstable dependency renders memoization ineffective📍 ui/ts/hooks/useZoltarFork.ts:158 The useLayoutEffect used for data fetching📍 ui/ts/hooks/useZoltarUniverse.ts:175 The effect loads remote data (Zoltar universe and question count), which is a side effect unrelated to DOM measurements or synchronous layout. According to React/Preact best practices, data fetching should use useEffect to avoid blocking the browser paint and to follow the intended lifecycle. Using useLayoutEffect for this can cause unnecessary synchronous work before paint and misrepresents the intent of the effect. Decimals=0 not respected for tiny valuesWhen Fragile error message parsing in scalar validation📍 ui/ts/lib/marketCreation.ts:187 The validateMarketForm function uses string inclusion checks on error messages from parseScalarFormInputs to assign field errors to specific form fields. This couples validation logic to the exact wording of error messages, making it brittle—any change to those messages will break field error assignment and lead to incorrect user feedback. It also violates the principle of avoiding magic strings for control flow, reducing maintainability and testability. Incomplete normalization for negative decimal inputs📍 ui/ts/lib/scalarOutcome.ts:21 The Inconsistent test organization for formatRoundedCurrencyBalance📍 ui/ts/tests/formatters.test.ts:24 The test suite scatters tests for the same function across different levels: existing tests for formatRoundedCurrencyBalance are direct children of the 'formatting helpers' describe, while new tests are added in a nested describe for a specific scenario. This violates the best practice of grouping all tests for a single unit together, making it harder to locate, understand, and maintain all test cases for that function. Consistent organization improves readability and reduces cognitive load when working with the test suite. Test suite mixes multiple function units under a single describe block📍 ui/ts/tests/migrationOutcomeUniversesSection.test.ts:8 The describe block is named 'getMigrationOutcomeHeldBalance' but contains tests for both getMigrationOutcomeHeldBalance and getMigrationOutcomeSplitLimit. This reduces clarity and makes it harder to locate tests for a specific function. Separate describe blocks should be used for each unit under test to improve maintainability and readability. Test name typo: 'quoteEthForToken' should be 'quoteExactInput'📍 ui/ts/tests/uniswapQuoter.integration.test.ts:71 The test on line 71 is named 'quoteEthForToken(USDC via REP) throws for all standard fee tiers' but it calls Remove redundant double type assertions📍 ui/ts/tests/uniswapQuoter.test.ts:28 The code uses the 'as unknown as T' pattern in two places, which is an anti-pattern that unnecessarily bypasses TypeScript's type checking. A single assertion ('as T') or direct element access with a single assertion is sufficient and clearer. This improves maintainability and readability. |
Summary
Testing
ui/ts/tests/marketCreation.test.ts.ui/ts/tests/scalarOutcome.test.ts.