Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughA new bridge modal feature enables ETH transfers from Ethereum-compatible chains to Yominet through a modal UI component. Supporting infrastructure includes bridge API utilities, type definitions, wallet integration hooks, and validator state management updates to coordinate the bridging workflow. Changes
Sequence DiagramsequenceDiagram
participant User as User/UI
participant BridgeModal as BridgeModal Component
participant BridgeService as Bridge API
participant Wallet as EVM Wallet
participant SourceRPC as Source Chain RPC
participant YomiRPC as Yominet RPC
User->>BridgeModal: Opens bridge modal
BridgeModal->>BridgeService: getBridgeServiceStatus()
BridgeService-->>BridgeModal: health status
User->>BridgeModal: Selects chain & amount
BridgeModal->>SourceRPC: getNativeBalance(address)
SourceRPC-->>BridgeModal: balance
BridgeModal->>YomiRPC: getYominetEthBalance(address)
YomiRPC-->>BridgeModal: balance
User->>BridgeModal: Confirm bridge transaction
BridgeModal->>BridgeService: fetchBridgeRoute(request)
BridgeService-->>BridgeModal: route with operations
BridgeModal->>BridgeService: fetchBridgeMsgs(operations)
BridgeService-->>BridgeModal: EVM transaction payload
BridgeModal->>Wallet: switchNetwork(chainId)
Wallet-->>BridgeModal: network switched
BridgeModal->>Wallet: sendTransaction(txPayload)
Wallet-->>BridgeModal: txHash
loop Poll for completion (up to 40 attempts)
BridgeModal->>YomiRPC: getYominetEthBalance(address)
YomiRPC-->>BridgeModal: updated balance
alt Balance increased
BridgeModal-->>User: Bridge complete ✓
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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 Tip CodeRabbit can use Trivy to scan for security misconfigurations and secrets in Infrastructure as Code files.Add a .trivyignore file to your project to customize which findings Trivy reports. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/client/src/app/components/fixtures/menu/buttons/More.tsx (2)
36-36:⚠️ Potential issue | 🟡 MinorRemove duplicate semicolon.
There's a double semicolon
;;at the end ofhandleResetState. While JavaScript tolerates this, it's a code smell.Proposed fix
- };; + };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/app/components/fixtures/menu/buttons/More.tsx` at line 36, Remove the stray duplicate semicolon after the handleResetState function in More.tsx: locate the closing of the handleResetState implementation (symbol handleResetState) and delete the extra semicolon so the function end is terminated by a single semicolon (or none if consistent with surrounding style).
61-61:⚠️ Potential issue | 🟡 MinorRemove duplicate semicolon.
Same issue here at the end of
clearCache.Proposed fix
- };; + };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/app/components/fixtures/menu/buttons/More.tsx` at line 61, The function clearCache contains an extraneous duplicate semicolon (";;") at its end; remove the extra semicolon so only a single semicolon terminates the statement. Locate the clearCache function in the More component (symbol: clearCache) and delete the redundant semicolon to clean up the syntax.packages/client/types/ethers-contracts/NewbieVendorBuySystem.ts (1)
207-251:⚠️ Potential issue | 🔴 CriticalThe entire factories directory is missing, preventing the generated types from working.
The type file (
NewbieVendorBuySystem.ts) has been regenerated withcalcPrice, and the ABI JSON includes it. However,packages/client/types/ethers-contracts/factories/does not exist. Theindex.tsfile exportsNewbieVendorBuySystem__factoryfrom a non-existent directory, causing import failures. Regenerate the ethers contract factories.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/types/ethers-contracts/NewbieVendorBuySystem.ts` around lines 207 - 251, The generated types reference a missing factories directory and export NewbieVendorBuySystem__factory from a non-existent path; regenerate the ethers contract factories so the factory files (including NewbieVendorBuySystem__factory) are created and match the ABI (which contains calcPrice). Run the TypeChain/ethers factory generation command used by this repo (e.g., the project's codegen or typechain script) to recreate packages/client/types/ethers-contracts/factories/, then verify index.ts exports point to the newly generated NewbieVendorBuySystem__factory and update any mismatched export paths if needed.
🧹 Nitpick comments (10)
packages/client/src/app/components/modals/bridge/utils.ts (2)
7-16: Provider cache never evicts stale connections.If an RPC endpoint becomes unresponsive, the cached
JsonRpcProviderwill continue to be reused. For a long-running app, consider adding a simple TTL or connection health check.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/app/components/modals/bridge/utils.ts` around lines 7 - 16, The providerCache in getRpcProvider stores JsonRpcProvider instances indefinitely, so stale/unresponsive RPC connections get reused; update getRpcProvider/providerCache to evict or refresh entries by adding a TTL and health check: store a timestamp with each cached provider, on retrieval validate age and optionally perform a lightweight call (e.g., provider.getBlockNumber or a small health ping) to confirm responsiveness, and if the provider is too old or fails the health check create a new JsonRpcProvider, replace the cache entry, and return it; ensure you reference getRpcProvider, providerCache, and JsonRpcProvider when locating code to modify.
30-39: Consider adding error handling for RPC failures.Both
getNativeBalanceandgetYominetEthBalancepropagate RPC errors directly. Since these are polled every 5 seconds, transient network failures could disrupt the UI.♻️ Proposed error handling pattern
export async function getNativeBalance(rpcUrl: string, address: string): Promise<bigint> { + try { const provider = getRpcProvider(rpcUrl); return provider.getBalance(getAddress(address)); + } catch (error) { + console.warn(`Failed to fetch native balance from ${rpcUrl}:`, error); + throw error; // Let caller handle or return 0n as fallback + } } export async function getYominetEthBalance(address: string): Promise<bigint> { + try { const provider = getRpcProvider(YOMINET_RPC_URL); const contract = new Contract(YOMINET_ETH_TOKEN_ADDRESS, yominetEthAbi, provider); const balance = await contract.balanceOf(getAddress(address)); return toBigInt(balance); + } catch (error) { + console.warn('Failed to fetch Yominet ETH balance:', error); + throw error; + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/app/components/modals/bridge/utils.ts` around lines 30 - 39, Wrap the RPC calls in getNativeBalance and getYominetEthBalance with try/catch to handle transient RPC failures: catch errors from getRpcProvider()/provider.getBalance() and contract.balanceOf(), log the error (use existing logger or console.error) and return a safe fallback (e.g., 0n) instead of letting the error propagate and break the poller; keep existing helpers (getRpcProvider, getAddress, toBigInt, YOMINET_RPC_URL, YOMINET_ETH_TOKEN_ADDRESS, yominetEthAbi, Contract) when implementing the try/catch and fallback logic.packages/client/src/app/components/validators/AccountRegistrar/Registration.tsx (1)
17-18: Threshold inconsistency across bridge prompts.
BRIDGE_THRESHOLD_ETH = 0.001differs fromGasConstants.Empty(≈0.00001 ETH) used inGasHarasser.tsx(line 97) andFundOperator.tsx(line 87). Users with balances between 0.00001 and 0.001 ETH will be prompted to bridge during registration but not in other contexts.Consider either:
- Centralizing the bridge threshold constant in
constants/gas.tsfor consistency, or- Documenting why registration intentionally uses a higher threshold (e.g., ensuring enough gas for the full registration flow).
Also applies to: 55-57
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/app/components/validators/AccountRegistrar/Registration.tsx` around lines 17 - 18, BRIDGE_THRESHOLD_ETH in Registration.tsx (and the duplicated values at lines 55-57) is inconsistent with GasConstants.Empty used in GasHarasser.tsx and FundOperator.tsx; either centralize the threshold (create or use a single exported constant in constants/gas.ts, e.g., export const BRIDGE_THRESHOLD_ETH and replace the local const in Registration.tsx and other callers) or, if registration must intentionally use a higher value, replace the literal with a clearly named constant in constants/gas.ts and add a short inline comment documenting why registration requires the higher threshold so all modules reference the same symbol and behavior is consistent.packages/client/src/app/components/modals/bridge/types.ts (1)
8-18: Consider adding runtime validation forBridgeMsgsPayload.Per
packages/client/src/network/bridge.ts,fetchBridgeMsgsreturnsRecord<string, unknown>. InBridge.tsx:247-253, the response is cast directly toBridgeMsgsPayloadwithout validation. If the API returns an unexpected shape (missingtxsarray or differently structuredevm_tx), accessingevmTx.to,evmTx.value, etc. will fail silently or throw at runtime.Consider adding a type guard or validation function:
function isBridgeMsgsPayload(data: unknown): data is BridgeMsgsPayload { if (!data || typeof data !== 'object') return false; const obj = data as Record<string, unknown>; if (!Array.isArray(obj.txs)) return true; // txs is optional return obj.txs.every((tx) => typeof tx === 'object' && tx !== null ); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/app/components/modals/bridge/types.ts` around lines 8 - 18, Add runtime validation for BridgeMsgsPayload by implementing a type guard (e.g., isBridgeMsgsPayload) and using it where fetchBridgeMsgs' result is cast to BridgeMsgsPayload (code around the Bridge component handling the fetch). The guard should check that the top-level value is an object, that txs—if present—is an array, and that each tx is an object whose optional evm_tx (if present) contains the expected string fields (chain_id, to, value, data, optional signer_address). Replace the unchecked cast in the Bridge component (where the fetch result is cast to BridgeMsgsPayload) with a runtime check that only proceeds to read evm_tx.* when isBridgeMsgsPayload returns true, otherwise handle the error/invalid shape path.packages/client/src/app/components/modals/bridge/Bridge.tsx (2)
247-256: API response cast lacks validation.The
fetchBridgeMsgsresponse is cast toBridgeMsgsPayloadwithout runtime validation. If the API returns an unexpected structure, accessingevmTx.to,evmTx.value, orevmTx.dataon line 272-274 will fail at runtime.Consider validating the response structure before use, or adding more defensive checks around
evmTxproperty access.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/app/components/modals/bridge/Bridge.tsx` around lines 247 - 256, The code blindly casts fetchBridgeMsgs(...) to BridgeMsgsPayload and then assumes evmTx fields exist; add runtime validation after receiving msgs from fetchBridgeMsgs to ensure msgs is an object, msgs.txs is an array, find a tx with tx.evm_tx, and that the resulting evmTx has the required properties (to, value, data) before using them; if validation fails, throw a clear error (or handle fallback) instead of accessing undefined. Implement this with a small type guard or schema check around the existing fetchBridgeMsgs call and before the evmTx usage so functions and consumers like BridgeMsgsPayload, fetchBridgeMsgs, and evm_tx are protected from malformed API responses.
267-277: Validate transaction hash type.The
eth_sendTransactionresult is cast tostringwithout validation. While this typically returns a hex string, wallet implementations vary. A malformed response could cause issues in subsequent transaction tracking.Proposed defensive check
const hash = (await wallet.request({ method: 'eth_sendTransaction', params: [/* ... */], })) as string; + + if (typeof hash !== 'string' || !hash.startsWith('0x')) { + throw new Error('Wallet returned invalid transaction hash'); + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/app/components/modals/bridge/Bridge.tsx` around lines 267 - 277, The code casts the result of wallet.request(..., method: 'eth_sendTransaction') to string (variable hash) without validation; update the handler around the wallet.request call in Bridge.tsx to validate that the returned value is a string and a properly formatted hex transaction hash (e.g., typeof hash === 'string' and matches /^0x[0-9a-fA-F]+$/), and if not, log or throw a clear error (including the raw response) so subsequent tracking logic that relies on hash (the hash variable and any follow-up functions that track the transaction from evmTx) doesn’t operate on malformed data; also consider normalizing or rejecting non-prefixed values before using them.packages/client/src/network/bridge.ts (4)
1-3: Consider making API URLs configurable via environment variables.Hardcoded URLs make it difficult to switch between environments (development, staging, production). Extracting these to environment variables improves deployment flexibility.
♻️ Suggested approach
-export const ROUTER_API_BASE_URL = 'https://router-api.initia.xyz/v2/fungible'; -export const BRIDGE_STATUS_URL = - 'https://opinit-api-yominet-1.anvil.asia-southeast.initia.xyz/status'; +export const ROUTER_API_BASE_URL = + process.env.NEXT_PUBLIC_ROUTER_API_BASE_URL ?? 'https://router-api.initia.xyz/v2/fungible'; +export const BRIDGE_STATUS_URL = + process.env.NEXT_PUBLIC_BRIDGE_STATUS_URL ?? + 'https://opinit-api-yominet-1.anvil.asia-southeast.initia.xyz/status';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/network/bridge.ts` around lines 1 - 3, Replace the hardcoded constants ROUTER_API_BASE_URL and BRIDGE_STATUS_URL with values read from environment variables (e.g., process.env.ROUTER_API_BASE_URL and process.env.BRIDGE_STATUS_URL) and provide sensible defaults so existing behavior remains unchanged; update the export lines for ROUTER_API_BASE_URL and BRIDGE_STATUS_URL to use the env fallback pattern and add brief comments indicating the env var names so deployments can override them for dev/staging/prod.
124-143: Add timeout to status check fetch.Same concern as
postRouterApi- the fetch has no timeout and could hang indefinitely if the status endpoint is unresponsive.♻️ Suggested fix
try { const response = await fetch(BRIDGE_STATUS_URL, { method: 'GET', headers: { 'Content-Type': 'application/json' }, + signal: AbortSignal.timeout(10_000), });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/network/bridge.ts` around lines 124 - 143, The getBridgeServiceStatus function lacks a fetch timeout and can hang; modify getBridgeServiceStatus to use an AbortController and pass its signal to fetch(BRIDGE_STATUS_URL), start a timer (e.g., 5s or configurable) that calls controller.abort() on timeout, clear the timer when fetch completes, and ensure the catch block handles the abort case (return healthy: false with an appropriate detail message) while still delegating JSON parsing to interpretBridgeHealth for successful responses.
54-72: Add request timeout to prevent indefinite hangs.The
fetchcall has no timeout configured. If the bridge API becomes unresponsive, requests will hang indefinitely, potentially freezing the UI. Consider usingAbortSignal.timeout()for automatic cancellation.♻️ Suggested fix with timeout
async function postRouterApi<TResponse>( path: 'route' | 'msgs', body: Record<string, unknown> ): Promise<TResponse> { const response = await fetch(`${ROUTER_API_BASE_URL}/${path}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body), + signal: AbortSignal.timeout(30_000), }); if (!response.ok) { const error = await response.text().catch(() => ''); throw new Error(`Bridge ${path} request failed (${response.status}): ${error}`); } return (await response.json()) as TResponse; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/network/bridge.ts` around lines 54 - 72, The postRouterApi function currently uses fetch without a timeout which can hang; update it to create an AbortSignal with a finite timeout (e.g., via AbortSignal.timeout(ms)) and pass that signal to fetch so the request is automatically aborted on timeout, then handle the abort case by catching the error and throwing a clear Error including that it timed out; modify postRouterApi to accept or create the timeout value, use AbortSignal.timeout(...) as the signal option in fetch, and ensure the existing error path still returns the response body text or JSON appropriately.
99-122: Consider logging unknown response shapes for observability.Defaulting to
healthy: truefor unknown shapes avoids false-negative failures, but could silently mask API changes or issues. Adding a warning log when falling through to the default would aid debugging without changing the fail-safe behavior.💡 Optional enhancement
// Unknown shape: avoid false negative hard-fail. + console.warn('[bridge] Unknown health response shape, assuming healthy:', payload); return { healthy: true }; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/client/src/network/bridge.ts` around lines 99 - 122, interpretBridgeHealth currently returns { healthy: true } for unknown payload shapes without any logging; add a non-breaking warning log right before that return so observability captures unexpected responses. In the interpretBridgeHealth function, when falling through to the default return, call the existing logger (or introduce a module logger if none exists) to warn with context including the raw payload and that BridgeServiceStatus parsing failed, but do not change the returned value or flow; reference the function name interpretBridgeHealth and the BridgeServiceStatus return to locate where to insert the log.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/client/src/app/components/modals/bridge/Bridge.tsx`:
- Line 302: In Bridge.tsx update the call to setStatusText inside the Bridge
component so the success message includes proper punctuation and spacing (e.g.,
change the string passed to setStatusText('Bridge Complete Congratulations') to
a properly punctuated sentence like "Bridge complete. Congratulations."). Locate
the setStatusText invocation in the Bridge component and replace the message
string accordingly.
- Around line 283-306: The polling loop in Bridge.tsx (POLL_MAX_ATTEMPTS)
continues after the modal closes, causing API calls and state updates on an
unmounted component; fix it by wiring an abort/check into the loop: create an
AbortController stored in a ref (or reuse an existing ref), pass its signal to
any async helpers (getBridgeServiceStatus/getYominetEthBalance) or check the
ref.signal.aborted, and on modal close (isOpen -> false) call
controller.abort(); additionally, inside the loop check isOpen (or
controller.signal.aborted) before awaiting or calling setters
(setIsServiceDegraded/setYomiBalance/setStatusText/setIsBridging) and break
early to avoid updates after unmount.
- Around line 241-242: The code is using routeAmountOut and amountOut without
guaranteeing either exists before calling fetchBridgeMsgs; update the Bridge.tsx
logic around routeAmountOut/amountOut to explicitly validate and handle missing
values: locate the lines that compute routeAmountOut and amountOut and either
(a) set a safe fallback (e.g. convert to a validated numeric/zero string) or (b)
return/throw/early-exit and surface a user-facing error if both amount_out and
amount_in are absent, and ensure you only call fetchBridgeMsgs when amountOut is
a defined, acceptable value; adjust any related UI/error state so
fetchBridgeMsgs never receives undefined.
---
Outside diff comments:
In `@packages/client/src/app/components/fixtures/menu/buttons/More.tsx`:
- Line 36: Remove the stray duplicate semicolon after the handleResetState
function in More.tsx: locate the closing of the handleResetState implementation
(symbol handleResetState) and delete the extra semicolon so the function end is
terminated by a single semicolon (or none if consistent with surrounding style).
- Line 61: The function clearCache contains an extraneous duplicate semicolon
(";;") at its end; remove the extra semicolon so only a single semicolon
terminates the statement. Locate the clearCache function in the More component
(symbol: clearCache) and delete the redundant semicolon to clean up the syntax.
In `@packages/client/types/ethers-contracts/NewbieVendorBuySystem.ts`:
- Around line 207-251: The generated types reference a missing factories
directory and export NewbieVendorBuySystem__factory from a non-existent path;
regenerate the ethers contract factories so the factory files (including
NewbieVendorBuySystem__factory) are created and match the ABI (which contains
calcPrice). Run the TypeChain/ethers factory generation command used by this
repo (e.g., the project's codegen or typechain script) to recreate
packages/client/types/ethers-contracts/factories/, then verify index.ts exports
point to the newly generated NewbieVendorBuySystem__factory and update any
mismatched export paths if needed.
---
Nitpick comments:
In `@packages/client/src/app/components/modals/bridge/Bridge.tsx`:
- Around line 247-256: The code blindly casts fetchBridgeMsgs(...) to
BridgeMsgsPayload and then assumes evmTx fields exist; add runtime validation
after receiving msgs from fetchBridgeMsgs to ensure msgs is an object, msgs.txs
is an array, find a tx with tx.evm_tx, and that the resulting evmTx has the
required properties (to, value, data) before using them; if validation fails,
throw a clear error (or handle fallback) instead of accessing undefined.
Implement this with a small type guard or schema check around the existing
fetchBridgeMsgs call and before the evmTx usage so functions and consumers like
BridgeMsgsPayload, fetchBridgeMsgs, and evm_tx are protected from malformed API
responses.
- Around line 267-277: The code casts the result of wallet.request(..., method:
'eth_sendTransaction') to string (variable hash) without validation; update the
handler around the wallet.request call in Bridge.tsx to validate that the
returned value is a string and a properly formatted hex transaction hash (e.g.,
typeof hash === 'string' and matches /^0x[0-9a-fA-F]+$/), and if not, log or
throw a clear error (including the raw response) so subsequent tracking logic
that relies on hash (the hash variable and any follow-up functions that track
the transaction from evmTx) doesn’t operate on malformed data; also consider
normalizing or rejecting non-prefixed values before using them.
In `@packages/client/src/app/components/modals/bridge/types.ts`:
- Around line 8-18: Add runtime validation for BridgeMsgsPayload by implementing
a type guard (e.g., isBridgeMsgsPayload) and using it where fetchBridgeMsgs'
result is cast to BridgeMsgsPayload (code around the Bridge component handling
the fetch). The guard should check that the top-level value is an object, that
txs—if present—is an array, and that each tx is an object whose optional evm_tx
(if present) contains the expected string fields (chain_id, to, value, data,
optional signer_address). Replace the unchecked cast in the Bridge component
(where the fetch result is cast to BridgeMsgsPayload) with a runtime check that
only proceeds to read evm_tx.* when isBridgeMsgsPayload returns true, otherwise
handle the error/invalid shape path.
In `@packages/client/src/app/components/modals/bridge/utils.ts`:
- Around line 7-16: The providerCache in getRpcProvider stores JsonRpcProvider
instances indefinitely, so stale/unresponsive RPC connections get reused; update
getRpcProvider/providerCache to evict or refresh entries by adding a TTL and
health check: store a timestamp with each cached provider, on retrieval validate
age and optionally perform a lightweight call (e.g., provider.getBlockNumber or
a small health ping) to confirm responsiveness, and if the provider is too old
or fails the health check create a new JsonRpcProvider, replace the cache entry,
and return it; ensure you reference getRpcProvider, providerCache, and
JsonRpcProvider when locating code to modify.
- Around line 30-39: Wrap the RPC calls in getNativeBalance and
getYominetEthBalance with try/catch to handle transient RPC failures: catch
errors from getRpcProvider()/provider.getBalance() and contract.balanceOf(), log
the error (use existing logger or console.error) and return a safe fallback
(e.g., 0n) instead of letting the error propagate and break the poller; keep
existing helpers (getRpcProvider, getAddress, toBigInt, YOMINET_RPC_URL,
YOMINET_ETH_TOKEN_ADDRESS, yominetEthAbi, Contract) when implementing the
try/catch and fallback logic.
In
`@packages/client/src/app/components/validators/AccountRegistrar/Registration.tsx`:
- Around line 17-18: BRIDGE_THRESHOLD_ETH in Registration.tsx (and the
duplicated values at lines 55-57) is inconsistent with GasConstants.Empty used
in GasHarasser.tsx and FundOperator.tsx; either centralize the threshold (create
or use a single exported constant in constants/gas.ts, e.g., export const
BRIDGE_THRESHOLD_ETH and replace the local const in Registration.tsx and other
callers) or, if registration must intentionally use a higher value, replace the
literal with a clearly named constant in constants/gas.ts and add a short inline
comment documenting why registration requires the higher threshold so all
modules reference the same symbol and behavior is consistent.
In `@packages/client/src/network/bridge.ts`:
- Around line 1-3: Replace the hardcoded constants ROUTER_API_BASE_URL and
BRIDGE_STATUS_URL with values read from environment variables (e.g.,
process.env.ROUTER_API_BASE_URL and process.env.BRIDGE_STATUS_URL) and provide
sensible defaults so existing behavior remains unchanged; update the export
lines for ROUTER_API_BASE_URL and BRIDGE_STATUS_URL to use the env fallback
pattern and add brief comments indicating the env var names so deployments can
override them for dev/staging/prod.
- Around line 124-143: The getBridgeServiceStatus function lacks a fetch timeout
and can hang; modify getBridgeServiceStatus to use an AbortController and pass
its signal to fetch(BRIDGE_STATUS_URL), start a timer (e.g., 5s or configurable)
that calls controller.abort() on timeout, clear the timer when fetch completes,
and ensure the catch block handles the abort case (return healthy: false with an
appropriate detail message) while still delegating JSON parsing to
interpretBridgeHealth for successful responses.
- Around line 54-72: The postRouterApi function currently uses fetch without a
timeout which can hang; update it to create an AbortSignal with a finite timeout
(e.g., via AbortSignal.timeout(ms)) and pass that signal to fetch so the request
is automatically aborted on timeout, then handle the abort case by catching the
error and throwing a clear Error including that it timed out; modify
postRouterApi to accept or create the timeout value, use
AbortSignal.timeout(...) as the signal option in fetch, and ensure the existing
error path still returns the response body text or JSON appropriately.
- Around line 99-122: interpretBridgeHealth currently returns { healthy: true }
for unknown payload shapes without any logging; add a non-breaking warning log
right before that return so observability captures unexpected responses. In the
interpretBridgeHealth function, when falling through to the default return, call
the existing logger (or introduce a module logger if none exists) to warn with
context including the raw payload and that BridgeServiceStatus parsing failed,
but do not change the returned value or flow; reference the function name
interpretBridgeHealth and the BridgeServiceStatus return to locate where to
insert the log.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2f43cde9-ffc9-49f0-9a5d-4fe39e8b1fd4
📒 Files selected for processing (21)
packages/client/abi/NewbieVendorBuySystem.jsonpackages/client/index.htmlpackages/client/src/app/components/fixtures/menu/buttons/More.tsxpackages/client/src/app/components/index.tspackages/client/src/app/components/library/modals/ModalWrapper.tsxpackages/client/src/app/components/modals/FundOperator.tsxpackages/client/src/app/components/modals/bridge/Bridge.tsxpackages/client/src/app/components/modals/bridge/constants.tspackages/client/src/app/components/modals/bridge/index.tspackages/client/src/app/components/modals/bridge/types.tspackages/client/src/app/components/modals/bridge/utils.tspackages/client/src/app/components/validators/AccountRegistrar/AccountRegistrar.tsxpackages/client/src/app/components/validators/AccountRegistrar/Registration.tsxpackages/client/src/app/components/validators/GasHarasser.tsxpackages/client/src/app/components/validators/WalletConnector/WalletConnector.tsxpackages/client/src/app/stores/visibility.tspackages/client/src/network/bridge.tspackages/client/src/network/hooks/useBridgeOpener.tspackages/client/src/network/utils/hooks.tspackages/client/types/ethers-contracts/NewbieVendorBuySystem.tspackages/client/types/ethers-contracts/index.ts
💤 Files with no reviewable changes (1)
- packages/client/src/network/utils/hooks.ts
| const routeAmountOut = (route as { amount_out?: unknown }).amount_out; | ||
| const amountOut = typeof routeAmountOut === 'string' ? routeAmountOut : route.amount_in; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check if BridgeRouteResponse guarantees amount_out or amount_in fields
# Search for the response type definition
rg -n -A10 'BridgeRouteResponse' packages/client/src/network/bridge.tsRepository: Asphodel-OS/kamigotchi
Length of output: 1101
🏁 Script executed:
# Read the Bridge.tsx file around lines 241-242 with context
sed -n '230,260p' packages/client/src/app/components/modals/bridge/Bridge.tsxRepository: Asphodel-OS/kamigotchi
Length of output: 1536
Validate amountOut before passing to fetchBridgeMsgs.
Since BridgeRouteResponse only guarantees operations and uses Record<string, unknown> for other fields, neither amount_out nor amount_in are required. If both are missing, amountOut will be undefined and passed to fetchBridgeMsgs at line 248, which likely doesn't accept undefined values.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/client/src/app/components/modals/bridge/Bridge.tsx` around lines 241
- 242, The code is using routeAmountOut and amountOut without guaranteeing
either exists before calling fetchBridgeMsgs; update the Bridge.tsx logic around
routeAmountOut/amountOut to explicitly validate and handle missing values:
locate the lines that compute routeAmountOut and amountOut and either (a) set a
safe fallback (e.g. convert to a validated numeric/zero string) or (b)
return/throw/early-exit and surface a user-facing error if both amount_out and
amount_in are absent, and ensure you only call fetchBridgeMsgs when amountOut is
a defined, acceptable value; adjust any related UI/error state so
fetchBridgeMsgs never receives undefined.
| for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) { | ||
| let pollIntervalMs = POLL_INTERVAL_MS; | ||
| if (attempt % STATUS_RECHECK_EVERY_ATTEMPTS === 0) { | ||
| const pollServiceStatus = await getBridgeServiceStatus(); | ||
| const degraded = !pollServiceStatus.healthy; | ||
| setIsServiceDegraded(degraded); | ||
|
|
||
| if (degraded) { | ||
| pollIntervalMs = DEGRADED_POLL_INTERVAL_MS; | ||
| setStatusText( | ||
| 'Bridge submitted. Service is degraded right now, so this may take longer.' | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)); | ||
| const nextBalance = await getYominetEthBalance(selectedAddress); | ||
| setYomiBalance(nextBalance); | ||
| if (nextBalance > baseline) { | ||
| setStatusText('Bridge Complete Congratulations'); | ||
| setIsBridging(false); | ||
| return; | ||
| } | ||
| } |
There was a problem hiding this comment.
Polling continues after modal is closed.
If the user closes the modal during the polling loop (lines 283-306), the loop continues executing API calls and state updates on an unmounted component. This wastes resources and can cause React warnings about state updates on unmounted components.
Consider adding an abort signal or checking isOpen within the loop:
Proposed fix using AbortController pattern
const startBridge = async () => {
+ const abortController = new AbortController();
+ const signal = abortController.signal;
+
// ... existing code ...
const baseline = latestBalances.yomi;
for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) {
+ if (signal.aborted) return;
+
let pollIntervalMs = POLL_INTERVAL_MS;
// ... rest of loop ...
}
};You'll also need to store the controller in a ref and abort it when isOpen becomes false.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/client/src/app/components/modals/bridge/Bridge.tsx` around lines 283
- 306, The polling loop in Bridge.tsx (POLL_MAX_ATTEMPTS) continues after the
modal closes, causing API calls and state updates on an unmounted component; fix
it by wiring an abort/check into the loop: create an AbortController stored in a
ref (or reuse an existing ref), pass its signal to any async helpers
(getBridgeServiceStatus/getYominetEthBalance) or check the ref.signal.aborted,
and on modal close (isOpen -> false) call controller.abort(); additionally,
inside the loop check isOpen (or controller.signal.aborted) before awaiting or
calling setters
(setIsServiceDegraded/setYomiBalance/setStatusText/setIsBridging) and break
early to avoid updates after unmount.
| const nextBalance = await getYominetEthBalance(selectedAddress); | ||
| setYomiBalance(nextBalance); | ||
| if (nextBalance > baseline) { | ||
| setStatusText('Bridge Complete Congratulations'); |
There was a problem hiding this comment.
Fix completion message formatting.
The success message is missing punctuation between sentences.
Proposed fix
- setStatusText('Bridge Complete Congratulations');
+ setStatusText('Bridge complete. Congratulations!');📝 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.
| setStatusText('Bridge Complete Congratulations'); | |
| setStatusText('Bridge complete. Congratulations!'); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/client/src/app/components/modals/bridge/Bridge.tsx` at line 302, In
Bridge.tsx update the call to setStatusText inside the Bridge component so the
success message includes proper punctuation and spacing (e.g., change the string
passed to setStatusText('Bridge Complete Congratulations') to a properly
punctuated sentence like "Bridge complete. Congratulations."). Locate the
setStatusText invocation in the Bridge component and replace the message string
accordingly.
544dc36 to
803f708
Compare
8cf8c4e to
fee9141
Compare
- Add BridgeFundStep: after bridge success, prompt user to fund operator directly from bridge modal (reserves 0.0002 ETH for gas) - Rewrite GasHarasser & FundOperator inputs: text-based decimal input with regex validation, smart tier defaults, StepButton +/-, clear-on-focus/blur-to-restore - Add reusable StepButton component (press-and-hold increment/decrement) - Restyle BridgeForm inputs to match: ETH icons, StepButtons, 0.001 minimum - Fix loading flashes: accountChecked gate, isLive/burnerAddress guards in AccountRegistrar, operatorHasGas default true - Fix OperatorUpdater false trigger: dead-address guard, skip button - Fix ValidatorWrapper ExitButton using wrong store key (id vs divName) - Fix wallet switch stale state: clear account store and query caches on logout - Fix Settings modal showing dead addresses before account creation - Fix bridge check regression: restore useTokens (ERC20 ETH) instead of useBalance (native) for needsToBridge - Enforce 0.001 ETH minimum on bridge amount (input, blur, nudge, and prefill)
4d30485 to
41ce8d5
Compare
Summary by CodeRabbit
Release Notes
New Features
Improvements