Conversation
devop: fix Encryption Excempt
…nto feat/safari-support
fix: Removed unnecessary link to `.entitlemens` (duplicate)
fix(signers): rename test suite from Ethereum to Bitcoin signing
…jection for Opera
…adability and maintainability
There was a problem hiding this comment.
Actionable comments posted: 3
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (19)
packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue (2)
285-387:⚠️ Potential issue | 🟠 MajorPrevent the loading screen from getting stuck on early failures.
If
network.value.api(),decodeTx, or other awaited calls throw beforegetGasCosts(), the currentfinallynever runs. That leavesisLoadingtrue anderrorMsgempty.✅ Suggested structure
-onBeforeMount(async () => { - const { Request, options } = await windowPromise; +onBeforeMount(async () => { + try { + const { Request, options } = await windowPromise; network.value = (await getNetworkByName( Request.value.params![2], )) as EvmNetwork; @@ - await decodeTx( + const decoded = await decodeTx( Request.value.params![0] as EthereumTransaction, network.value as EvmNetwork, - ).then(decoded => { + ); + { const realToAddress = decoded.tokenTo || decoded.toAddress || ''; @@ - decodedTx.value = decoded; + decodedTx.value = decoded; fiatValue.value = new BigNumber( fromBase(decoded.tokenValue, decoded.tokenDecimals), ) .times(decoded.currentPriceUSD) .toFixed(2); - }); + } @@ - await tx - .getGasCosts() - .then(async gasvals => { + const gasvals = await tx.getGasCosts(); + { let nativeVal = '0'; @@ - selectedFee.value = GasPriceTypes.REGULAR; - }) - .catch(e => { - errorMsg.value = e.message; - }) - .finally(() => { - isLoading.value = false; - }); + selectedFee.value = GasPriceTypes.REGULAR; + } + } catch (e: any) { + errorMsg.value = e?.message ?? 'Failed to load transaction'; + } finally { + isLoading.value = false; + } });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue` around lines 285 - 387, The loading flag is only cleared in the .finally() of tx.getGasCosts(), so early throws from network.value.api(), decodeTx(), or other awaits leave isLoading true and errorMsg empty; wrap the entire onBeforeMount async body in a try/catch/finally (or add a top-level try around the awaited calls inside onBeforeMount) so any thrown error is caught and sets errorMsg.value = e.message and the finally always sets isLoading.value = false; target the onBeforeMount handler and ensure catches cover network.value.api(), decodeTx(...), and Transaction.getGasCosts() failures, leaving isLoading and errorMsg updated accordingly.
290-293:⚠️ Potential issue | 🟠 MajorFix the default fee selection condition.
Line 290 uses
network.value.name === NetworkNames.Ethereum || NetworkNames.Binance, which always evaluates truthy and forcesREGULARfor all networks (and for failure paths where later overrides don’t run).✅ Proposed fix
- selectedFee.value = - network.value.name === NetworkNames.Ethereum || NetworkNames.Binance - ? GasPriceTypes.REGULAR - : GasPriceTypes.ECONOMY; + selectedFee.value = + network.value.name === NetworkNames.Ethereum || + network.value.name === NetworkNames.Binance + ? GasPriceTypes.REGULAR + : GasPriceTypes.ECONOMY;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue` around lines 290 - 293, The condition that sets selectedFee.value wrongly uses "network.value.name === NetworkNames.Ethereum || NetworkNames.Binance" which always evaluates truthy; change it to explicitly compare network.value.name to both constants (e.g., network.value.name === NetworkNames.Ethereum || network.value.name === NetworkNames.Binance) or use an inclusion check (e.g., [NetworkNames.Ethereum, NetworkNames.Binance].includes(network.value.name)) so that selectedFee.value is REGULAR only for those two networks and ECONOMY otherwise; update the assignment around selectedFee.value and keep GasPriceTypes.REGULAR / GasPriceTypes.ECONOMY as the branches.packages/extension/src/providers/solana/ui/send-transaction/index.vue (1)
455-475:⚠️ Potential issue | 🟠 MajorMissing
.catch()onfetchAssets— user gets stuck on loading spinner if the network call fails.If
props.network.getAllTokens()rejects,isLoadingAssetsstaystruepermanently and the user sees the loading spinner forever with no way to proceed or retry.🐛 Proposed fix
return props.network.getAllTokens(addressFrom.value).then(allAssets => { accountAssets.value = allAssets as SOLToken[]; const hasParamData = isSendToken.value && tokenParamData && tokenParamData.contract; if (hasParamData) { const selectedToken = accountAssets.value.find( asset => asset.contract === tokenParamData.contract, ); if (selectedToken) { selectedAsset.value = selectedToken as SOLToken; } } else { selectedAsset.value = allAssets[0] as SOLToken; } isLoadingAssets.value = false; + }).catch((err) => { + console.error('Failed to fetch assets:', err); + isLoadingAssets.value = false; });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/solana/ui/send-transaction/index.vue` around lines 455 - 475, The fetchAssets function currently returns props.network.getAllTokens(...) without handling rejection, so isLoadingAssets.value can remain true; wrap the network call with a .catch handler (on the Promise returned by props.network.getAllTokens) to set isLoadingAssets.value = false, reset accountAssets.value and selectedAsset.value (e.g., to [] and loadingAsset), and optionally log the error; ensure the .catch is chained to the same Promise returned by fetchAssets (or use try/catch if converted to async) so any rejection clears the loading state and allows retry.packages/extension/src/providers/ethereum/ui/send-transaction/components/send-token-select.vue (1)
2-17:⚠️ Potential issue | 🟠 MajorUse a semantic button to keep keyboard access intact.
<a>withouthrefis not focusable, so keyboard users can't open the token picker. Replace it with<button type="button">and add focus-visible styling.Suggested fix (semantic button + focus-visible)
- <a class="send-token-select" `@click`="emit('update:toggleTokenSelect')"> + <button + type="button" + class="send-token-select" + `@click`="emit('update:toggleTokenSelect')" + > <div class="send-token-select__image"> <img :src="token.icon" alt="" /> </div> <div class="send-token-select__info"> <h5>{{ token.name }}</h5> <p> {{ balance ? $filters.formatFloatingPointValue(balance).value : '~' }} <span>{{ token.symbol }}</span> </p> </div> <div class="send-token-select__arrow"> <switch-arrow /> </div> - </a> + </button>.send-token-select { height: 60px; background: `@white`; margin: 0 24px 8px 24px; box-sizing: border-box; border: 1.5px solid rgba(98, 126, 234, 0.15); border-radius: 14px; width: calc(~'100% - 48px'); padding: 12px 16px; display: flex; justify-content: flex-start; align-items: center; flex-direction: row; position: relative; cursor: pointer; text-decoration: none; transition: all 200ms ease-in-out; box-shadow: 0 2px 8px rgba(98, 126, 234, 0.06); + font: inherit; + color: inherit; + + &:focus-visible { + outline: 2px solid rgba(98, 126, 234, 0.6); + outline-offset: 2px; + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/ethereum/ui/send-transaction/components/send-token-select.vue` around lines 2 - 17, The anchor element with class "send-token-select" is non-semantic and not keyboard-focusable; replace the outer <a> with a <button type="button"> (preserving the `@click` handler that triggers emit('update:toggleTokenSelect')) so the token picker is keyboard-accessible, keep inner structure (send-token-select__image, __info, __arrow and the <switch-arrow />) and add focus-visible styling (e.g., a focus-visible class or :focus-visible styles) to the "send-token-select" element to provide visible keyboard focus.packages/extension/src/ui/provider-pages/enkrypt/unlock-keyring.vue (1)
97-113:⚠️ Potential issue | 🟠 MajorMissing
.catch()leaves the UI permanently locked on rejection
sendToBackground(...)is not awaited and has no.catch()handler. If the promise rejects (background script crash, Safari extension messaging failure, etc.),isProcessing.valueis never reset tofalse, permanently disabling both the Unlock button (viaisDisabled) and the Forgot password button (via:disabled="isProcessing"). The user has no recovery path without reloading the popup.Additionally,
errorMsg.valueis set on the error branch but is never exposed in the template — only the booleanisErroris passed tolock-screen-password-input, so the specific error message from the background is silently discarded.🐛 Proposed fix — add `.catch()` and reset processing state
const approve = async () => { isProcessing.value = true; const { sendToBackground, Resolve } = await windowPromise; sendToBackground({ method: InternalMethods.unlock, params: [password.value, false], - }).then(res => { + }).then(res => { if (res.error) { errorMsg.value = res.error.message; isError.value = true; isProcessing.value = false; } else { Resolve.value({ result: JSON.stringify(res.result), }); } - }); + }).catch(() => { + isError.value = true; + isProcessing.value = false; + }); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/ui/provider-pages/enkrypt/unlock-keyring.vue` around lines 97 - 113, The approve handler leaves isProcessing true on promise rejection and discards the background error message; change it to await the sendToBackground call (or add a .catch()) and ensure isProcessing.value is reset in a finally block, set isError.value and populate errorMsg.value from the caught error, and then surface errorMsg by passing it into the lock-screen-password-input component (currently only isError is passed) so the UI shows the specific error; locate symbols approve, sendToBackground, Resolve, isProcessing, errorMsg, isError, windowPromise and update the promise handling and template binding accordingly.packages/extension/src/providers/ethereum/ui/eth-decrypt.vue (1)
152-169:⚠️ Potential issue | 🟠 MajorHandle background call failures and reset
isProcessing.If
sendToBackgroundrejects (orwindowPromisefails), the UI can get stuck in “Decrypting…” with no resolution path.🛠️ Suggested fix with try/catch/finally
const approve = async () => { if (isProcessing.value) return; isProcessing.value = true; - const { Request, sendToBackground, Resolve } = await windowPromise; - const encryptedMessage = Request.value.params![0] as string; - sendToBackground({ - method: InternalMethods.ethereumDecrypt, - params: [encryptedMessage, account.value], - }).then(res => { - if (res.error) { - Resolve.value(res); - } else { - Resolve.value({ - result: JSON.stringify(res.result), - }); - } - }); + try { + const { Request, sendToBackground, Resolve } = await windowPromise; + const encryptedMessage = Request.value.params![0] as string; + const res = await sendToBackground({ + method: InternalMethods.ethereumDecrypt, + params: [encryptedMessage, account.value], + }); + if (res.error) { + Resolve.value(res); + } else { + Resolve.value({ result: JSON.stringify(res.result) }); + } + } catch (e) { + console.error(e); + } finally { + isProcessing.value = false; + } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/ethereum/ui/eth-decrypt.vue` around lines 152 - 169, The approve handler can leave isProcessing.value true and never call Resolve.value if windowPromise or sendToBackground rejects; wrap the await windowPromise and the sendToBackground call in a try/catch/finally inside the approve function (referencing approve, windowPromise, Request, sendToBackground, Resolve, isProcessing) so that any thrown error results in Resolve.value being called with an error object in the catch, and ensure isProcessing.value is reset to false in finally; also handle the successful path as before but keep the Resolve.value calls inside the try block.packages/extension/src/providers/ethereum/ui/send-transaction/verify-transaction/index.vue (1)
329-345:⚠️ Potential issue | 🟠 MajorRemove
-webkit-text-fill-color: transparentand related properties from the h3 rule.The h3 header text will be invisible. The gradient text effect requires a
backgroundproperty that isn't present in this rule. Thecolor:@primaryLabel`` is overridden by-webkit-text-fill-color: transparent, rendering the text transparent without a background to show through. Similar patterns in other files (network-activity-total.vue, send-header.vue) all include an explicit `background: linear-gradient()` property; this file is missing it. Remove the text-fill and background-clip overrides.🛠️ Safe fix (remove transparent text fill)
h3 { font-style: normal; font-weight: 700; font-size: 22px; line-height: 28px; color: `@primaryLabel`; margin: 0; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/ethereum/ui/send-transaction/verify-transaction/index.vue` around lines 329 - 345, In the h3 rule inside verify-transaction/index.vue remove the gradient-related overrides so the header isn't rendered transparent: delete -webkit-text-fill-color: transparent, -webkit-background-clip: text and background-clip: text and keep color: `@primaryLabel` (or add an explicit background: linear-gradient(...) if you intend a gradient); target the h3 selector in that file (the h3 CSS block) when making the change.packages/swap/src/providers/okx/index.ts (1)
719-738:⚠️ Potential issue | 🟡 MinorRemove the misleading inline comment on line 732; clarify that
chainIndexis optional.The main comment at line 719 is actually correct—OKX v6 API docs confirm
chainIndexis not required. However, the inline comment on line 732 (// required for swap API) is misleading since the code sends it despite it being optional. Either remove that inline comment or clarify why it's being sent (e.g.,// Sent for context even though optional).The
slippagePercentparameter and format are correct: it's a percentage value (0–100), and the code correctly usesDEFAULT_SLIPPAGE = "0.5"to represent 0.5%.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/swap/src/providers/okx/index.ts` around lines 719 - 738, The inline comment on the chainIndex field in the swapParams object is misleading (it currently reads "// Solana Chain ID - required for swap API"); update it to reflect that chainIndex is optional in OKX v6 (e.g., change to "// Solana Chain ID - optional (included for context)" or remove the "required" wording) so the swapParams declaration (chainIndex, amount, fromTokenAddress, toTokenAddress, userWalletAddress, slippagePercent, swapMode) accurately reflects API expectations; keep the existing logic that converts NATIVE_TOKEN_ADDRESS to SOL_NATIVE_ADDRESS and the slippagePercent formatting using DEFAULT_SLIPPAGE as-is.packages/name-resolution/package.json (1)
44-46:⚠️ Potential issue | 🟡 MinorUnfilled placeholder in
repository.url.
"url": "git+https://github.com/<FILL_IT>"is a stale placeholder that has never been replaced with the actual repository URL. Should be corrected to the canonical URL (e.g., matching the pattern used in other packages).🔧 Proposed fix
- "url": "git+https://github.com/<FILL_IT>" + "url": "git+https://github.com/enkryptcom/enKrypt/tree/main/packages/name-resolution"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/name-resolution/package.json` around lines 44 - 46, Replace the placeholder repository URL in package.json: update the "repository" object's "url" value (currently "git+https://github.com/<FILL_IT>") to the canonical GitHub repo URL used by other packages (e.g., the real git+https://github.com/your-org/your-repo.git) so the repository.url field is accurate and consistent across packages.packages/name-resolution/tests/resolver.test.ts (1)
22-24:⚠️ Potential issue | 🟡 MinorCommented-out assertion silently masks a regression.
The expected address for
spaceid.arb(0xb5932a6B7d50A966AEC6C74C97385412Fb497540) is commented out and replaced withnull. This means the test is now passing with degraded behavior (resolution returningnull) with no tracking or signal. Either re-enable the assertion once the resolution issue is fixed, or document this as a known gap with a linked issue.Would you like me to open an issue to track this spaceid.arb resolution regression?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/name-resolution/tests/resolver.test.ts` around lines 22 - 24, The test currently masks a regression by asserting expect(address).to.be.eq(null) after calling resolver.resolveAddress("spaceid.arb", "ARB1"); restore the original expectation to expect(address).to.be.eq("0xb5932a6B7d50A966AEC6C74C97385412Fb497540") in packages/name-resolution/tests/resolver.test.ts (re-enable the commented assertion) so the test fails if resolution regresses; if the resolution is known broken, instead mark the specific test as skipped (e.g., test.skip or add a clear TODO) and create/link an issue tracking the regression in the test comment so the gap is discoverable.packages/signers/bitcoin/package.json (1)
21-37:⚠️ Potential issue | 🟠 MajorAlign
engines.nodewith the new toolchain baseline.
typescript-eslintv8.56.0 explicitly requires Node 18.18.0+ (viaengines.node), while this package declares support for Node >=14.15.0. Additionally,@types/nodev25 targets Node 25.x. Updateengines.nodeto reflect the actual minimum supported version (Node 18.18.0 or later), or downgrade the toolchain to match Node 14/16 support.Example alignment (Node 18.18.0+)
"engines": { - "node": ">=14.15.0" + "node": ">=18.18.0" }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/signers/bitcoin/package.json` around lines 21 - 37, The package's declared engines.node (engines.node in package.json) is outdated relative to devDependencies (typescript-eslint v8.56.0 and `@types/node` v25) — update the engines.node value in package.json to at least ">=18.18.0" (or another minimum Node version you choose that matches the toolchain) so it aligns with the requirements of `@typescript-eslint` and `@types/node`; modify the engines.node field and commit so package metadata accurately reflects the new Node baseline used by the devDependencies.packages/extension/src/providers/bitcoin/ui/send-transaction/index.vue (1)
310-317:⚠️ Potential issue | 🟠 MajorGuard against empty asset lists to avoid undefined selectedAsset.
allAssets[0]can beundefined; later usages (selectedAsset.value.decimals!) will throw. Add a fallback (or show an empty state) when the list is empty.🐛 Proposed fix
return props.network.getAllTokens(addressFrom.value).then(allAssets => { accountAssets.value = allAssets as BTCToken[]; - selectedAsset.value = allAssets[0] as BTCToken; + selectedAsset.value = (allAssets[0] as BTCToken) ?? loadingAsset; isLoadingAssets.value = false; });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/bitcoin/ui/send-transaction/index.vue` around lines 310 - 317, fetchAssets currently assumes props.network.getAllTokens(addressFrom.value) returns a non-empty array and assigns allAssets[0] to selectedAsset, which can be undefined; update fetchAssets to guard against an empty array by checking allAssets.length before assigning selectedAsset (fall back to loadingAsset or a clear/empty state), ensure accountAssets is set to allAssets, set isLoadingAssets.value = false in all code paths, and ensure subsequent code paths that read selectedAsset.value.decimals use the safe fallback or handle a null/empty selectedAsset; reference fetchAssets, selectedAsset, accountAssets, props.network.getAllTokens, and addressFrom to locate and fix the logic.packages/extension/src/providers/bitcoin/ui/send-transaction/components/send-token-select.vue (1)
2-28:⚠️ Potential issue | 🟠 MajorUse a semantic
<button>element for keyboard accessibility.
<a>withouthrefis not focusable via keyboard and lacks semantic meaning for interactive actions. Replace with<button type="button">to ensure keyboard users can access this component and to maintain proper HTML semantics.🔧 Proposed fix
- <a class="send-token-select" `@click`="emit('update:toggleTokenSelect')"> + <button + type="button" + class="send-token-select" + `@click`="emit('update:toggleTokenSelect')" + > ... - </a> + </button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/bitcoin/ui/send-transaction/components/send-token-select.vue` around lines 2 - 28, The root element of the SendTokenSelect component is an <a> without href which is not keyboard-focusable; replace it with a semantic <button type="button" class="send-token-select" `@click`="emit('update:toggleTokenSelect')"> so keyboard users can activate it. Keep the same class and click handler (emit('update:toggleTokenSelect')), ensure any CSS targeting .send-token-select still applies to a button (adjust selectors if necessary), and preserve the child structure including the <switch-arrow /> import and defineEmits usage.packages/extension/src/providers/ethereum/ui/send-transaction/index.vue (4)
68-74:⚠️ Potential issue | 🟡 Minor
:is-loadingprop is structurally dead — alwaysfalsewhen rendered.
AssetsSelectListlives insidev-if="!!selected && !isLoadingAssets"(line 11), soisLoadingAssetsis guaranteed to befalsewhenever this component is in the DOM. WhenselectAccountFromtriggers a re-fetch, the whole.send-transactionblock unmounts beforeisLoadingAssetsflips back totrue. The:is-loadingbinding here can never betrue.🔧 Proposed fix
<assets-select-list v-model="isOpenSelectToken" :is-send="true" :assets="accountAssets" - :is-loading="isLoadingAssets" `@update`:select-asset="selectToken" />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/ethereum/ui/send-transaction/index.vue` around lines 68 - 74, The :is-loading binding on AssetsSelectList is dead because the parent v-if ("!!selected && !isLoadingAssets") guarantees isLoadingAssets is false whenever AssetsSelectList is mounted; either remove the unnecessary :is-loading="isLoadingAssets" prop from the AssetsSelectList usage or move AssetsSelectList outside the v-if so it can observe loading transitions during selectAccountFrom re-fetches; update the template where AssetsSelectList is used (the <assets-select-list ... /> with v-model="isOpenSelectToken", :assets="accountAssets" and `@update`:select-asset="selectToken") and ensure the component either receives a meaningful loading prop or the parent controls its visibility consistently.
561-581:⚠️ Potential issue | 🟠 Major
fetchAssetshas no rejection handler — network failure leaves the user on an infinite loading screen.If
getAllTokensrejects (RPC error, timeout, etc.),isLoadingAssetsnever resets tofalse. The loading spinner stays forever with no error message or recovery. The same gap affects the call-sites inonMounted(line 313) andselectAccountFrom(line 731).🛡️ Proposed fix
return props.network.getAllTokens(addressFrom.value).then(allAssets => { accountAssets.value = allAssets as (Erc20Token & { contract: string })[]; const hasParamData = isSendToken.value && tokenParamData && tokenParamData.contract; if (hasParamData) { const selectedToken = accountAssets.value.find( asset => asset.contract === tokenParamData.contract, ); if (selectedToken) { selectedAsset.value = selectedToken as Erc20Token; } } else { selectedAsset.value = allAssets[0] as Erc20Token; } isLoadingAssets.value = false; - }); + }).catch(e => { + console.error('Error fetching assets', e); + isLoadingAssets.value = false; + // optionally surface an error state to the user + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/ethereum/ui/send-transaction/index.vue` around lines 561 - 581, fetchAssets currently returns props.network.getAllTokens(...) without any rejection handling so a rejected promise leaves isLoadingAssets.value true; wrap the await/then call in a try/catch (or append a .catch) inside fetchAssets to ensure isLoadingAssets.value is set to false in both success and failure paths, log or surface the error (e.g., set an error state or call the component's notification/logging method) and rethrow or return a safe value so callers (onMounted and selectAccountFrom) can react; update fetchAssets (and its usages in onMounted/selectAccountFrom) to handle the propagated error instead of relying on the spinner to resolve itself.
575-579:⚠️ Potential issue | 🔴 Critical
allAssets[0]isundefinedwhengetAllTokensreturns an empty array, crashing all downstreamselectedAssetaccesses.
allAssets[0] as Erc20Tokenjust casts away the undefined — afterisLoadingAssetsflips tofalsethe form renders and immediately throws TypeErrors inhasEnoughBalance,errorMsg,TxInfo,sendButtonTitle, etc.🐛 Proposed fix
} else { - selectedAsset.value = allAssets[0] as Erc20Token; + if (allAssets.length > 0) { + selectedAsset.value = allAssets[0] as Erc20Token; + } + // else: leave loadingAsset in place or surface a "no assets" error state }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/ethereum/ui/send-transaction/index.vue` around lines 575 - 579, The code sets selectedAsset.value = allAssets[0] as Erc20Token even when getAllTokens returns an empty array, which causes downstream TypeErrors; change the assignment to check array length first (if allAssets.length > 0 set selectedAsset.value = allAssets[0] else set selectedAsset.value = undefined/null) and ensure the component state (isLoadingAssets, errorMsg/hasEnoughBalance/TxInfo/sendButtonTitle) treats selectedAsset as possibly undefined (update types if needed) so the UI disables actions or shows a friendly message when no tokens are available.
267-271:⚠️ Potential issue | 🟠 Major
|| NetworkNames.Binanceis always truthy —selectedFeedefaults toREGULARfor every network.
NetworkNames.Binanceis a non-empty string constant, so the OR is alwaystrueand the ternary always returnsGasPriceTypes.REGULAR, regardless of the actual network. Any network intended to start onECONOMYsilently getsREGULARfees.🐛 Proposed fix
const selectedFee = ref<GasPriceTypes>( - props.network.name === NetworkNames.Ethereum || NetworkNames.Binance + props.network.name === NetworkNames.Ethereum || props.network.name === NetworkNames.Binance ? GasPriceTypes.REGULAR : GasPriceTypes.ECONOMY, );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/ethereum/ui/send-transaction/index.vue` around lines 267 - 271, The ternary condition initializing selectedFee uses "props.network.name === NetworkNames.Ethereum || NetworkNames.Binance" which always truthy; update the condition to explicitly compare props.network.name to both constants (e.g. props.network.name === NetworkNames.Ethereum || props.network.name === NetworkNames.Binance) so networks truly match and selectedFee picks REGULAR only for those two, otherwise ECONOMY; keep references to selectedFee, GasPriceTypes, props.network.name, NetworkNames.Ethereum and NetworkNames.Binance when locating the code.packages/extension/src/providers/ethereum/ui/eth-get-encryption-key.vue (1)
153-169:⚠️ Potential issue | 🟠 MajorHandle promise rejections and always clear
isProcessingwith try/catch/finally.The
await windowPromiseat line 157 could reject, leaving the UI stuck in "Providing..." and never resolving the request. Additionally,isProcessingflag is never reset on any error path. Wrap the code intry/catch/finallyto ensure the flag is cleared.Note: The error code to use in the catch block should be one from the existing
ErrorCodesenum (userRejected,unauthorized,unsupportedMethod,disconnected, orchainDisconnected) orgetCustomError()for a custom message—there is nointernalerror code constant. This same issue exists ineth-decrypt.vue.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/providers/ethereum/ui/eth-get-encryption-key.vue` around lines 153 - 169, The approve handler (approve) must guard against rejected windowPromise and failures from sendToBackground and always reset isProcessing; wrap the logic in try/catch/finally, await windowPromise and await sendToBackground (or handle its rejection) instead of relying solely on .then, and in catch call Resolve.value with an error object using an existing ErrorCodes enum value (or getCustomError()) to report the failure; ensure isProcessing.value is set to false in finally. Apply the same change pattern to the similar handler in eth-decrypt.vue.packages/extension/src/ui/action/views/network-assets/components/network-assets-item.vue (1)
99-141:⚠️ Potential issue | 🟡 MinorUse
computedfor chart options to ensure reactivity when token prop updates.Currently,
optionis a staticrefcreated at setup time. When the token prop updates (e.g., during market data refresh or asset list re-render), the chart won't reflect changes because the option object itself doesn't update. The parent component reassigns the entire assets array, which passes new token objects to this component, but the frozen ref won't respond. Other components in the same codebase (e.g.,network-activity-total.vue) already usecomputed(() => ({ ... }))for this exact pattern, which properly tracks prop dependencies.Additionally, defensively handle potential invalid JSON in
sparklineby wrappingJSON.parsein a try-catch, though the current flow viaJSON.stringifyshould produce valid data.♻️ Suggested refactor
-const option = ref({ +const option = computed(() => ({ width: 56, height: 24, - color: [props.token.priceChangePercentage >= 0 ? '#22c55e' : '#ef4444'], + color: [props.token.priceChangePercentage >= 0 ? '#22c55e' : '#ef4444'], grid: { show: false, left: 0, top: 0, right: 0, bottom: 0 }, xAxis: [ { show: false, type: 'category', showGrid: false, boundaryGap: false, splitLine: { show: false }, }, ], yAxis: [ { show: false, type: 'value', splitLine: { show: false }, }, ], series: [ { type: 'line', smooth: true, lineStyle: { width: 1.5 }, areaStyle: { opacity: 0.1, - color: props.token.priceChangePercentage >= 0 ? '#22c55e' : '#ef4444', + color: props.token.priceChangePercentage >= 0 ? '#22c55e' : '#ef4444', }, showSymbol: false, emphasis: { focus: 'none' }, data: - props.token.sparkline !== '' ? JSON.parse(props.token.sparkline) : [], + parseSparklineData(props.token.sparkline), }, ], -}); +})); + +const parseSparklineData = (sparkline: string): number[] => { + if (!sparkline) return []; + try { + return JSON.parse(sparkline); + } catch { + return []; + } +};🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/extension/src/ui/action/views/network-assets/components/network-assets-item.vue` around lines 99 - 141, The chart `option` is created as a static ref and won't update when `props.token` changes; change `option` to a computed that returns the options object (e.g., computed(() => ({ ... })) ) and reference `props.token.priceChangePercentage` and parsed sparkline inside it so reactivity tracks prop updates; also defensively parse `props.token.sparkline` with a try-catch and return [] on parse errors so `series.data` never throws. Ensure you replace the existing `option = ref({...})` with the computed variant and keep the same keys (width, height, color, grid, xAxis, yAxis, series) so the chart consumer names (option, series.data) remain unchanged.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
.yarn/versions/81e941ed.ymlis excluded by!**/.yarn/**.yarn/versions/8cbbf8cb.ymlis excluded by!**/.yarn/**yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (90)
.yarnrc.ymlpackage.jsonpackages/extension-bridge/package.jsonpackages/extension/env.d.tspackages/extension/package.jsonpackages/extension/src/libs/dapp-list/index.tspackages/extension/src/providers/bitcoin/ui/send-transaction/components/send-address-input.vuepackages/extension/src/providers/bitcoin/ui/send-transaction/components/send-alert.vuepackages/extension/src/providers/bitcoin/ui/send-transaction/components/send-token-select.vuepackages/extension/src/providers/bitcoin/ui/send-transaction/index.vuepackages/extension/src/providers/common/ui/send-transaction/send-address-item.vuepackages/extension/src/providers/common/ui/send-transaction/send-contacts-list.vuepackages/extension/src/providers/common/ui/send-transaction/send-fee-select.vuepackages/extension/src/providers/common/ui/send-transaction/send-from-contacts-list.vuepackages/extension/src/providers/common/ui/send-transaction/send-header.vuepackages/extension/src/providers/common/ui/send-transaction/send-input-amount.vuepackages/extension/src/providers/common/ui/send-transaction/send-nft-select.vuepackages/extension/src/providers/common/ui/verify-transaction/verify-transaction-account.vuepackages/extension/src/providers/common/ui/verify-transaction/verify-transaction-amount.vuepackages/extension/src/providers/common/ui/verify-transaction/verify-transaction-fee.vuepackages/extension/src/providers/common/ui/verify-transaction/verify-transaction-network.vuepackages/extension/src/providers/ethereum/inject.tspackages/extension/src/providers/ethereum/libs/activity-handlers/index.tspackages/extension/src/providers/ethereum/libs/activity-handlers/providers/godwoken/configs.tspackages/extension/src/providers/ethereum/libs/activity-handlers/providers/godwoken/index.tspackages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.tspackages/extension/src/providers/ethereum/libs/assets-handlers/token-lists.tspackages/extension/src/providers/ethereum/libs/assets-handlers/types/tokenbalance-mew.tspackages/extension/src/providers/ethereum/networks/5ire.tspackages/extension/src/providers/ethereum/networks/godwoken.tspackages/extension/src/providers/ethereum/networks/index.tspackages/extension/src/providers/ethereum/tests/ethereum.events.test.tspackages/extension/src/providers/ethereum/tests/ethereum.requests.test.tspackages/extension/src/providers/ethereum/ui/eth-connect-dapp.vuepackages/extension/src/providers/ethereum/ui/eth-decrypt.vuepackages/extension/src/providers/ethereum/ui/eth-get-encryption-key.vuepackages/extension/src/providers/ethereum/ui/eth-sign-message.vuepackages/extension/src/providers/ethereum/ui/eth-sign-typedata.vuepackages/extension/src/providers/ethereum/ui/eth-verify-transaction.vuepackages/extension/src/providers/ethereum/ui/send-transaction/components/send-address-input.vuepackages/extension/src/providers/ethereum/ui/send-transaction/components/send-alert.vuepackages/extension/src/providers/ethereum/ui/send-transaction/components/send-token-select.vuepackages/extension/src/providers/ethereum/ui/send-transaction/index.vuepackages/extension/src/providers/ethereum/ui/send-transaction/verify-transaction/index.vuepackages/extension/src/providers/ethereum/ui/styles/common-popup.lesspackages/extension/src/providers/polkadot/networks/assethub/assethub-dot.tspackages/extension/src/providers/polkadot/networks/assethub/assethub-ksm.tspackages/extension/src/providers/polkadot/networks/index.tspackages/extension/src/providers/polkadot/networks/unique/quartz.tspackages/extension/src/providers/solana/ui/send-transaction/components/send-address-input.vuepackages/extension/src/providers/solana/ui/send-transaction/components/send-alert.vuepackages/extension/src/providers/solana/ui/send-transaction/components/send-fee-select.vuepackages/extension/src/providers/solana/ui/send-transaction/components/send-token-select.vuepackages/extension/src/providers/solana/ui/send-transaction/index.vuepackages/extension/src/ui/action/composables/account-info.tspackages/extension/src/ui/action/views/asset-detail-view/index.vuepackages/extension/src/ui/action/views/network-activity/components/network-activity-action.vuepackages/extension/src/ui/action/views/network-activity/components/network-activity-loading.vuepackages/extension/src/ui/action/views/network-activity/components/network-activity-total.vuepackages/extension/src/ui/action/views/network-activity/components/network-activity-transaction.vuepackages/extension/src/ui/action/views/network-activity/components/transaction-timer.vuepackages/extension/src/ui/action/views/network-activity/index.vuepackages/extension/src/ui/action/views/network-assets/components/network-assets-item.vuepackages/extension/src/ui/action/views/network-assets/index.vuepackages/extension/src/ui/action/views/send-process/components/send-process-account.vuepackages/extension/src/ui/action/views/send-process/components/send-process-amount.vuepackages/extension/src/ui/action/views/send-process/components/send-process-nft.vuepackages/extension/src/ui/action/views/send-process/index.vuepackages/extension/src/ui/provider-pages/enkrypt/unlock-keyring.vuepackages/hw-wallets/package.jsonpackages/hw-wallets/src/trezor/trezorConnect.tspackages/keyring/package.jsonpackages/name-resolution/package.jsonpackages/name-resolution/tests/ens.test.tspackages/name-resolution/tests/resolver.test.tspackages/request/package.jsonpackages/signers/bitcoin/package.jsonpackages/signers/bitcoin/tests/sign.test.tspackages/signers/ethereum/package.jsonpackages/signers/kadena/package.jsonpackages/signers/massa/package.jsonpackages/signers/polkadot/package.jsonpackages/storage/package.jsonpackages/swap/package.jsonpackages/swap/src/configs.tspackages/swap/src/index.tspackages/swap/src/providers/okx/index.tspackages/types/package.jsonpackages/types/src/networks.tspackages/utils/package.json
💤 Files with no reviewable changes (13)
- packages/extension/src/providers/ethereum/libs/assets-handlers/token-lists.ts
- packages/extension/src/providers/ethereum/libs/assets-handlers/types/tokenbalance-mew.ts
- packages/extension/src/providers/ethereum/networks/index.ts
- packages/extension/src/providers/ethereum/networks/5ire.ts
- packages/extension/src/providers/ethereum/libs/activity-handlers/providers/godwoken/configs.ts
- packages/types/src/networks.ts
- packages/extension/src/providers/ethereum/libs/activity-handlers/index.ts
- packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts
- packages/extension/src/libs/dapp-list/index.ts
- packages/extension/src/providers/polkadot/networks/index.ts
- packages/extension/src/providers/ethereum/libs/activity-handlers/providers/godwoken/index.ts
- packages/extension/src/providers/polkadot/networks/unique/quartz.ts
- packages/extension/src/providers/ethereum/networks/godwoken.ts
| const approve = async () => { | ||
| if (isProcessing.value) return; | ||
| const { Request, Resolve } = await windowPromise; |
There was a problem hiding this comment.
TOCTOU race: set isProcessing = true before the await.
The guard at line 154 checks isProcessing.value synchronously, but the flag is only set to true at line 157, after await windowPromise. Because JavaScript suspends at each await, two rapid clicks can both pass the if (isProcessing.value) return check before either call reaches the flag assignment — sending two signatures for a single user intent.
🔒 Proposed fix: move the flag before the first `await`
const approve = async () => {
if (isProcessing.value) return;
+ isProcessing.value = true;
const { Request, Resolve } = await windowPromise;
const msg = Request.value.params![0] as `0x{string}`;
- isProcessing.value = true;
MessageSigner({📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const approve = async () => { | |
| if (isProcessing.value) return; | |
| const { Request, Resolve } = await windowPromise; | |
| const approve = async () => { | |
| if (isProcessing.value) return; | |
| isProcessing.value = true; | |
| const { Request, Resolve } = await windowPromise; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/extension/src/providers/ethereum/ui/eth-sign-message.vue` around
lines 153 - 155, The approve handler has a TOCTOU race: move the isProcessing
flag before the await to prevent concurrent runs — in the approve function
(reference: approve, isProcessing, windowPromise) set isProcessing.value = true
immediately after the synchronous guard and before awaiting windowPromise, and
wrap the async work in try/catch/finally to ensure isProcessing.value is reset
to false in the finally block (and rethrow or handle errors in catch) so the
flag is always cleared even on failure.
| <modal-forgot | ||
| v-if="isForgot" | ||
| :is-forgot="isForgot" | ||
| @toggle:forgot="toggleForgot" | ||
| :disabled="isProcessing" | ||
| /> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find the modal-forgot component file
fd -e vue "modal-forgot" | head -20Repository: enkryptcom/enKrypt
Length of output: 44
🏁 Script executed:
#!/bin/bash
# Search for modal-forgot references in the codebase
rg "modal-forgot" --type vue -A 3 -B 3Repository: enkryptcom/enKrypt
Length of output: 89
🏁 Script executed:
#!/bin/bash
# Search for modal-forgot in all files
rg "modal-forgot" -A 3 -B 3Repository: enkryptcom/enKrypt
Length of output: 7447
🏁 Script executed:
#!/bin/bash
# Read the complete modal-forgot component
cat -n packages/extension/src/ui/action/views/modal-forgot/index.vueRepository: enkryptcom/enKrypt
Length of output: 1848
🏁 Script executed:
#!/bin/bash
# Find and read lock-screen-forgot component
cat -n packages/extension/src/ui/action/views/lock-screen/components/lock-screen-forgot.vueRepository: enkryptcom/enKrypt
Length of output: 5136
Remove :disabled="isProcessing" from <modal-forgot> or declare the prop in the component
The :disabled="isProcessing" attribute is not declared as a prop in the modal-forgot component. Since modal-forgot uses v-bind="$attrs" and doesn't set inheritAttrs: false, the attribute falls through to lock-screen-forgot, which also doesn't declare it. This results in the disabled attribute being applied as an HTML attribute to the root <div> element, which is non-semantic and has no effect.
The lock-screen-forgot component manages its button's disabled state internally via a computed property (isDisabled), so the external disabled prop is unused. Either remove the attribute if it's not needed, or properly declare disabled as a prop in modal-forgot and wire it through the component hierarchy.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/extension/src/ui/provider-pages/enkrypt/unlock-keyring.vue` around
lines 55 - 60, The template passes :disabled="isProcessing" into <modal-forgot>
but that prop is not declared and falls through to lock-screen-forgot as an HTML
attribute; either remove the attribute from the usage or declare and forward a
proper prop. Fix by deleting :disabled="isProcessing" from the <modal-forgot>
invocation in unlock-keyring.vue if external disabling is unused, or add a
disabled prop to the modal-forgot component (e.g., props: { disabled: Boolean })
and pass it down/consume it (or explicitly forward it to lock-screen-forgot) so
the disabled state is handled via the components’ computed logic instead of
becoming a stray HTML attribute. Ensure modal-forgot’s implementation uses the
declared prop (or sets inheritAttrs: false and v-bind="$attrs" intentionally)
and that lock-screen-forgot receives/uses the prop if needed.
| const DEFAULT_TOKEN_ACCOUNT_RENT_EXEMPTION = 2039280; | ||
| const SOL_NATIVE_ADDRESS = "11111111111111111111111111111111"; | ||
| const OKX_API_URL = "https://partners.mewapi.io/okxswapv5"; | ||
| const OKX_API_URL = "https://partners.mewapi.io/okxswapv6"; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n packages/swap/src/providers/okx/index.ts | head -100Repository: enkryptcom/enKrypt
Length of output: 3690
🏁 Script executed:
sed -n '480,495p; 524,535p; 727,742p' packages/swap/src/providers/okx/index.tsRepository: enkryptcom/enKrypt
Length of output: 1620
🌐 Web query:
OKX DEX Aggregator v6 API base URL endpoints all-tokens quote swap
💡 Result:
OKX DEX Aggregator V6 REST base URL (aggregator): https://web3.okx.com/api/v6/dex/aggregator [1]
Endpoints (full URLs):
- All tokens:
GET https://web3.okx.com/api/v6/dex/aggregator/all-tokens[1] - Quote:
GET https://web3.okx.com/api/v6/dex/aggregator/quote[2] - Swap:
GET https://web3.okx.com/api/v6/dex/aggregator/swap[3]
Sources:
[1] https://web3.okx.com/ar/build/dev-docs/wallet-api/dex-get-tokens
[2] https://web3.okx.com/zh-hans/build/dev-docs/dex-api/dex-get-quote
[3] https://web3.okx.com/build/dev-docs/dex-api/dex-swap
Use official OKX v6 API base URL, not third-party proxy.
Line 50 uses https://partners.mewapi.io/okxswapv6 as the base URL, which is a third-party proxy (MEW) and not the official OKX DEX Aggregator v6 API. The official OKX v6 base URL is https://web3.okx.com/api/v6/dex/aggregator, with endpoints:
GET https://web3.okx.com/api/v6/dex/aggregator/all-tokensGET https://web3.okx.com/api/v6/dex/aggregator/quoteGET https://web3.okx.com/api/v6/dex/aggregator/swap
Confirm whether the MEW proxy is intentional and approved, or switch to the official OKX endpoint for v6.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/swap/src/providers/okx/index.ts` at line 50, Replace the third-party
proxy base URL constant OKX_API_URL with the official OKX DEX Aggregator v6 base
URL "https://web3.okx.com/api/v6/dex/aggregator"; update any code that
constructs paths (e.g., calls that append "/all-tokens", "/quote", "/swap") to
use OKX_API_URL so endpoints become OKX_API_URL + "/all-tokens" etc., and remove
or document the MEW proxy only if its usage was intentional/approved.
Summary by CodeRabbit
New Features
Bug Fixes
Chores