Conversation
WalkthroughAdds a VITE_FEATURE_FLAG_GNOSIS flag and gates inclusion of the Gnosis (chainId 100 / XDAI) entries across multiple modules (blockchain lists, networks, token lists, native symbols, stablecoins, explorers, and tests); also adds safe fallbacks for missing native token logos. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Env as import.meta.env
participant Core as utils/blockchain
participant Builder as all* builders
participant Consumer as UI/Services
Env->>Core: read VITE_FEATURE_FLAG_GNOSIS
Core->>Core: isGnosisEnabled = (flag === 'true')
Core->>Builder: build allSupported/allNative/allStable lists
alt isGnosisEnabled == true
Builder-->>Consumer: include chainId 100 entries
else
Builder-->>Consumer: filter out chainId 100 entries
end
Consumer->>Consumer: render networks, tokens, symbols, explorers
sequenceDiagram
autonumber
participant Caller as getBlockScan(100, isAddress)
participant Core as utils/blockchain
Caller->>Core: request explorer base for chainId 100
alt isGnosisEnabled == true
Core-->>Caller: "https://gnosisscan.io/{address|tx}/"
else
Core-->>Caller: "" (empty string)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying x with
|
| Latest commit: |
9e9e66f
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://5db9b139.x-e62.pages.dev |
| Branch Preview URL: | https://pro-3645-feature-flag-gnosis.x-e62.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/apps/deposit/components/AssetsList/AssetsList.tsx (1)
210-216: getDecimal may return a string on error; ensure numeric fallback to avoid NaN/typing issues.Both call sites assume a number; when getDecimal fails today it returns a string, causing parse/format failures.
- const tokenDecimals = await getDecimal(asset.tokenAddress, chainId); - const readableBalance = formatUnits( - BigInt(tokenBalance[0].balance), - Number(tokenDecimals || 18) - ); + const tokenDecimals = await getDecimal(asset.tokenAddress, chainId); + const decimalsToUse = + typeof tokenDecimals === 'number' && Number.isFinite(tokenDecimals) + ? tokenDecimals + : 18; + const readableBalance = formatUnits( + BigInt(tokenBalance[0].balance), + decimalsToUse + );-const readableBalance = formatUnits( - BigInt(newAssetBalance[0].balance), - Number(newAssetDecimals || 18) -); +const decimalsToUse = + typeof newAssetDecimals === 'number' && Number.isFinite(newAssetDecimals) + ? newAssetDecimals + : 18; +const readableBalance = formatUnits( + BigInt(newAssetBalance[0].balance), + decimalsToUse +);Also applies to: 294-297
src/apps/deposit/utils/blockchain.tsx (1)
199-227: getDecimal should return a number; current string fallback can break callers.Today on error it returns a string, propagating to parseUnits/formatUnits and causing runtime errors. Return a numeric fallback (18) and narrow the return type.
-export const getDecimal = async ( +export const getDecimal = async ( tokenAddress: string, chainId: number -): Promise<string | number> => { +): Promise<number> => { const chain = getNetworkViem(chainId); const chainUrl = chainMapping[chain.name.toLowerCase() as Network] || null; try { if (!chainUrl) { throw new Error(`Unsupported chain: ${chain.name}`); } const provider = createPublicClient({ chain, transport: http(chainUrl), }); const contract = getContract({ address: tokenAddress as `0x${string}`, abi: ERC20_ABI.abi, client: provider, }); const result = await contract.read.decimals(); - return result as number; + return Number(result); } catch (error) { - return `Error to get the decimal for token: ${tokenAddress}, ${error}`; + console.warn(`Falling back to 18 decimals for ${tokenAddress}:`, error); + return 18; } };And simplify the caller accordingly:
-const tokenDecimals = - selectedAsset && 'name' in selectedAsset - ? selectedAsset.decimals - : ((await getDecimal( - selectedAsset.tokenAddress, - Number(chainId) - )) as number) || 18; +const tokenDecimals = + selectedAsset && 'name' in selectedAsset + ? selectedAsset.decimals + : await getDecimal(selectedAsset.tokenAddress, Number(chainId));Also applies to: 360-366
🧹 Nitpick comments (15)
src/services/tokensData.ts (1)
351-355: Prefer undefined over empty-string fallback for missing token logos
Replacelogo: nativeAsset.logoURI || ''withlogo: nativeAsset.logoURI(orlogo: nativeAsset.logoURI ?? undefined) so that absent logos areundefinedrather than''. this prevents inadvertent<img src="" />in components that render unconditionally and lets existing guards (logo && <img>…) andImageWithFallbackhandle missing images correctly. Applies to lines 351–355 and 398–402 insrc/services/tokensData.ts.src/utils/blockchain.ts (3)
257-258: Fix brand casing: “GnosisScan”Use the official casing.
- return isGnosisEnabled ? 'Gnosisscan' : ''; + return isGnosisEnabled ? 'GnosisScan' : '';
278-279: Prefer a neutral name when disabledReturning the numeric id as a string can look odd in UI. Consider an empty string or “Unsupported”.
- return isGnosisEnabled ? 'Gnosis' : `${chain}`; + return isGnosisEnabled ? 'Gnosis' : '';
225-245: Nit: use HTTPS for ArbiscanMinor hardening and consistency with other explorers.
- case 42161: - return `http://arbiscan.io/${isAddress ? 'address' : 'tx'}/`; + case 42161: + return `https://arbiscan.io/${isAddress ? 'address' : 'tx'}/`;src/utils/__tests__/blockchain.test.ts (1)
20-24: Consider also asserting logoURI per chain.Small addition to strengthen coverage for native token metadata (name, symbol, logoURI).
src/apps/the-exchange/utils/blockchain.ts (2)
27-35: Use consistent symbol casing for XDAI.Elsewhere symbols use 'XDAI' (uppercase). Here it’s 'xDAI'. Standardize to avoid UI inconsistencies.
const allNativeSymbols: Record<number, string> = { - 100: 'xDAI', + 100: 'XDAI', };
37-41: Prefer satisfies over as for safer typing.Avoids promising keys that may be filtered out at runtime.
-export const NATIVE_SYMBOLS = Object.fromEntries( +export const NATIVE_SYMBOLS = Object.fromEntries( Object.entries(allNativeSymbols).filter( ([chainId]) => isGnosisEnabled || chainId !== '100' ) -) as Record<number, string>; +) satisfies Record<number, string>;src/apps/pulse/constants/tokens.ts (1)
3-11: Freeze addresses to prevent accidental mutation.Mark the list readonly for safety; no behavior change.
-const allStableCurrencies = [ +const allStableCurrencies = [ { chainId: 1, address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' }, { chainId: 10, address: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85' }, // USDC on Optimism { chainId: 137, address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359' }, // USDC on Polygon { chainId: 8453, address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' }, // USDC on Base { chainId: 42161, address: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' }, // USDC on Arbitrum { chainId: 56, address: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d' }, // USDC on BNB Smart Chain { chainId: 100, address: '0x2a22f9c3b484c3629090FeED35F17Ff8F88f76F0' }, // USDC on Gnosis -]; +] as const;src/apps/deposit/index.tsx (2)
42-42: DRY the feature flag source.Import isGnosisEnabled from a single utility (src/utils/blockchain.ts) to avoid divergence across files.
-const isGnosisEnabled = import.meta.env.VITE_FEATURE_FLAG_GNOSIS === 'true'; +import { isGnosisEnabled } from '../../utils/blockchain';
56-61: Type the networks without a cast.Infer a readonly tuple to drop the need for the explicit cast.
- networks: (isGnosisEnabled - ? allNetworks - : allNetworks.filter((n) => n.id !== gnosis.id)) as [ - typeof mainnet, - ...(typeof mainnet)[], - ], + networks: (isGnosisEnabled ? allNetworks : allNetworks.filter((n) => n.id !== gnosis.id)) as const,src/apps/deposit/components/AssetsList/AssetsList.tsx (1)
41-41: DRY the feature flag source.Reuse isGnosisEnabled from utils to keep behavior centralized.
-const isGnosisEnabled = import.meta.env.VITE_FEATURE_FLAG_GNOSIS === 'true'; +import { isGnosisEnabled } from '../../../utils/blockchain';src/apps/pillarx-app/components/TokensWithMarketDataTile/test/TokensWithMarketDataTile.test.tsx (2)
92-99: Use vi.stubEnv/vi.unstubAllEnvs and remove redundant conditional.You always stub GNOSIS to 'true', so the conditional is dead code. Prefer stubbing helpers and, if needed, split contexts for true/false.
- beforeEach(() => { - // Reset environment - Object.defineProperty(import.meta, 'env', { - value: { ...originalEnv, VITE_FEATURE_FLAG_GNOSIS: 'true' }, - writable: true, - }); - }); + beforeEach(() => { + vi.unstubAllEnvs(); + vi.stubEnv('VITE_FEATURE_FLAG_GNOSIS', 'true'); + }); - afterEach(() => { - // Reset environment - Object.defineProperty(import.meta, 'env', { - value: originalEnv, - writable: true, - }); - }); + afterEach(() => vi.unstubAllEnvs()); - // XDAI should only be present when Gnosis feature flag is enabled - if (import.meta.env.VITE_FEATURE_FLAG_GNOSIS === 'true') { - expect(mobileScreen.getAllByText('XDAI')).toHaveLength(2); - expect(mobileScreen.getByText('$1.4m')).toBeInTheDocument(); - expect(mobileScreen.getByText('$3,123')).toBeInTheDocument(); - expect(mobileScreen.getByText('$1.0622')).toBeInTheDocument(); // rounded up with limitDigitsNumber helper function - expect(mobileScreen.getByText('3.1%')).toBeInTheDocument(); - expect(mobileScreen.getByText('1423')).toBeInTheDocument(); - } + // XDAI present when GNOSIS is enabled + expect(mobileScreen.getAllByText('XDAI')).toHaveLength(2); + expect(mobileScreen.getByText('$1.4m')).toBeInTheDocument(); + expect(mobileScreen.getByText('$3,123')).toBeInTheDocument(); + expect(mobileScreen.getByText('$1.0622')).toBeInTheDocument(); // rounded up with limitDigitsNumber helper function + expect(mobileScreen.getByText('3.1%')).toBeInTheDocument(); + expect(mobileScreen.getByText('1423')).toBeInTheDocument();Also applies to: 100-107, 161-169
201-201: Fix typo in test name (“rowsd”).-it('renders the right number of rowsd', () => { +it('renders the right number of rows', () => {src/apps/pillarx-app/utils/constants.ts (1)
3-3: DRY the feature flag source.Use the shared isGnosisEnabled export for consistency with other modules.
-const isGnosisEnabled = import.meta.env.VITE_FEATURE_FLAG_GNOSIS === 'true'; +import { isGnosisEnabled } from '../../../utils/blockchain';src/apps/deposit/utils/blockchain.tsx (1)
37-37: DRY the feature flag source.Import isGnosisEnabled from utils to keep a single truth source.
-const isGnosisEnabled = import.meta.env.VITE_FEATURE_FLAG_GNOSIS === 'true'; +import { isGnosisEnabled } from '../../../utils/blockchain';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
src/apps/deposit/components/AssetsList/AssetsList.tsx(2 hunks)src/apps/deposit/index.tsx(1 hunks)src/apps/deposit/utils/blockchain.tsx(3 hunks)src/apps/pillarx-app/components/TokensWithMarketDataTile/test/TokensWithMarketDataTile.test.tsx(3 hunks)src/apps/pillarx-app/utils/constants.ts(2 hunks)src/apps/pulse/constants/tokens.ts(2 hunks)src/apps/pulse/utils/constants.ts(2 hunks)src/apps/the-exchange/components/DropdownTokensList/test/DropdownTokensList.test.tsx(0 hunks)src/apps/the-exchange/components/SelectDropdown/test/SelectDropdown.test.tsx(0 hunks)src/apps/the-exchange/utils/blockchain.ts(3 hunks)src/services/tokensData.ts(2 hunks)src/utils/__tests__/blockchain.test.ts(1 hunks)src/utils/blockchain.ts(11 hunks)
💤 Files with no reviewable changes (2)
- src/apps/the-exchange/components/SelectDropdown/test/SelectDropdown.test.tsx
- src/apps/the-exchange/components/DropdownTokensList/test/DropdownTokensList.test.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-05-23T14:44:33.911Z
Learnt from: RanaBug
PR: pillarwallet/x#315
File: src/apps/the-exchange/utils/wrappedTokens.ts:6-20
Timestamp: 2025-05-23T14:44:33.911Z
Learning: XDAI (Gnosis Chain) is intentionally excluded from the WRAPPED_NATIVE_TOKEN_ADDRESSES mapping in the exchange app's wrappedTokens utility.
Applied to files:
src/utils/blockchain.tssrc/apps/the-exchange/utils/blockchain.ts
🧬 Code graph analysis (8)
src/apps/deposit/index.tsx (1)
src/utils/blockchain.ts (1)
isGnosisEnabled(41-42)
src/utils/__tests__/blockchain.test.ts (1)
src/utils/blockchain.ts (1)
getNativeAssetForChainId(72-144)
src/apps/deposit/components/AssetsList/AssetsList.tsx (1)
src/utils/blockchain.ts (1)
isGnosisEnabled(41-42)
src/apps/pulse/constants/tokens.ts (1)
src/utils/blockchain.ts (1)
isGnosisEnabled(41-42)
src/apps/pillarx-app/utils/constants.ts (2)
src/utils/blockchain.ts (1)
isGnosisEnabled(41-42)src/types/api.ts (1)
PrimeAssetType(766-766)
src/apps/deposit/utils/blockchain.tsx (2)
src/utils/blockchain.ts (1)
isGnosisEnabled(41-42)src/apps/deposit/types/types.tsx (1)
Network(21-28)
src/apps/pulse/utils/constants.ts (1)
src/utils/blockchain.ts (1)
isGnosisEnabled(41-42)
src/apps/the-exchange/utils/blockchain.ts (1)
src/utils/blockchain.ts (1)
isGnosisEnabled(41-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: unit-tests
- GitHub Check: lint
- GitHub Check: build
🔇 Additional comments (8)
src/utils/blockchain.ts (3)
146-159: Gating strategy for supported/compatible chains looks solidThe filter pattern cleanly excludes chainId 100 when the flag is off.
Also applies to: 290-324
174-176: Logo gating is correctReturning the Gnosis logo only when enabled is consistent with visibility rules.
94-99: Sanity-check gating for Gnosis native asset
No calls togetNativeAssetForChainId(100)were found—confirm the actual native-asset lookup (e.g. yourgetNativeAssetfunction or mapping) is guarded byisGnosisEnabled(or asserts) so that, when Gnosis support is disabled, you never return the default POL asset for chain 100.src/apps/pulse/utils/constants.ts (1)
13-15: Mobula chain list gating is correctXDAI inclusion now respects the feature flag; default “All” path inherits CompatibleChains filtering.
src/apps/pulse/constants/tokens.ts (1)
13-15: LGTM: Gnosis gating via feature flag is correct.src/apps/pillarx-app/utils/constants.ts (1)
20-22: LGTM: simple, clear gating of XDAI in PRIME_ASSETS_MOBULA.src/apps/deposit/utils/blockchain.tsx (2)
71-75: Good guard: remapping Gnosis to mainnet when disabled.
122-167: Error handling looks solid; returns empty results rather than throwing.Good defensive coding around unsupported chains and RPC failures.
Also applies to: 169-196
| const tokenLists = Object.fromEntries( | ||
| Object.entries(allTokenLists).filter( | ||
| ([chainId]) => isGnosisEnabled || chainId !== '100' | ||
| ) | ||
| ); |
There was a problem hiding this comment.
Guard token list selection when Gnosis is disabled (prevents crash on chainId 100).
If a wallet is on Gnosis while the flag is off, tokenLists[100] is undefined and .tokens access throws. Use the remapped chain id from getNetworkViem and fallback safely.
- const balancesForChain = await getAllBalances(
- tokenLists[chainId as keyof typeof tokenLists].tokens as TokenList[]
- );
+ const effectiveChainId = getNetworkViem(chainId).id;
+ const list = tokenLists[effectiveChainId as keyof typeof tokenLists]?.tokens as TokenList[] | undefined;
+ if (!list) {
+ console.warn(`Token list not available for chainId ${chainId} (effective ${effectiveChainId}). Skipping.`);
+ setBalances([]);
+ return;
+ }
+ const balancesForChain = await getAllBalances(list);📝 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 tokenLists = Object.fromEntries( | |
| Object.entries(allTokenLists).filter( | |
| ([chainId]) => isGnosisEnabled || chainId !== '100' | |
| ) | |
| ); | |
| // ---- before (unchanged) ---- | |
| // (inside your async function, after defining `tokenLists` and `chainId`) | |
| // Replace this line: | |
| - const balancesForChain = await getAllBalances( | |
| - tokenLists[chainId as keyof typeof tokenLists].tokens as TokenList[] | |
| - ); | |
| // With the guarded, remapped‐chainId version: | |
| const effectiveChainId = getNetworkViem(chainId).id; | |
| const list = tokenLists[ | |
| effectiveChainId as keyof typeof tokenLists | |
| ]?.tokens as TokenList[] | undefined; | |
| if (!list) { | |
| console.warn( | |
| `Token list not available for chainId ${chainId} (effective ${effectiveChainId}). Skipping.` | |
| ); | |
| setBalances([]); | |
| return; | |
| } | |
| const balancesForChain = await getAllBalances(list); | |
| // ---- after (unchanged) ---- | |
| // (rest of your function) |
🤖 Prompt for AI Agents
In src/apps/deposit/components/AssetsList/AssetsList.tsx around lines 53 to 57,
the tokenLists construction/filtering allows chainId '100' to be excluded when
Gnosis is disabled which later leads to tokenLists[100] being undefined and
.tokens access throwing; update the filtering and subsequent access to use the
remapped chain id from getNetworkViem and add a safe fallback so you never
dereference undefined (e.g., remap the current chain id via getNetworkViem
before indexing tokenLists and use optional chaining or default to an empty
array when reading .tokens, or adjust the Object.entries filter to compare
against the remapped id rather than the raw '100').
| // Mock the environment variable | ||
| const originalEnv = import.meta.env; | ||
|
|
There was a problem hiding this comment.
Env mocking won’t affect isGnosisEnabled; module is evaluated before you mutate import.meta.env.
isGnosisEnabled is computed at import-time in src/utils/blockchain.ts. Since this test imports getNativeAssetForChainId before overriding env, both “enabled/disabled” cases will use the same cached value. Re-import the module after stubbing env, or mock the export directly.
Apply this restructuring to load fresh module state per scenario:
-import { gnosis, polygon } from 'viem/chains';
-import { getNativeAssetForChainId } from '../blockchain';
+import { gnosis, polygon } from 'viem/chains';
// Mock the environment variable
const originalEnv = import.meta.env;
describe('getNativeAssetForChainId', () => {
+ beforeEach(() => {
+ vi.unstubAllEnvs();
+ vi.resetModules();
+ });
afterEach(() => {
- // Reset environment
- Object.defineProperty(import.meta, 'env', {
- value: originalEnv,
- writable: true,
- });
+ vi.unstubAllEnvs();
+ Object.defineProperty(import.meta, 'env', { value: originalEnv, writable: true });
});
it('returns {POL} for polygon', async () => {
- const asset = getNativeAssetForChainId(polygon.id);
+ const { getNativeAssetForChainId } = await import('../blockchain');
+ const asset = getNativeAssetForChainId(polygon.id);
expect(asset.name).toBe('POL');
expect(asset.symbol).toBe('POL');
});
describe('when Gnosis feature flag is enabled', () => {
- beforeEach(() => {
- Object.defineProperty(import.meta, 'env', {
- value: { ...originalEnv, VITE_FEATURE_FLAG_GNOSIS: 'true' },
- writable: true,
- });
- });
+ beforeEach(() => vi.stubEnv('VITE_FEATURE_FLAG_GNOSIS', 'true'));
it('returns XDAI for Gnosis', async () => {
- const asset = getNativeAssetForChainId(gnosis.id);
+ const { getNativeAssetForChainId } = await import('../blockchain');
+ const asset = getNativeAssetForChainId(gnosis.id);
expect(asset.name).toBe('XDAI');
expect(asset.symbol).toBe('XDAI');
});
});
describe('when Gnosis feature flag is disabled', () => {
- beforeEach(() => {
- Object.defineProperty(import.meta, 'env', {
- value: { ...originalEnv, VITE_FEATURE_FLAG_GNOSIS: 'false' },
- writable: true,
- });
- });
+ beforeEach(() => vi.stubEnv('VITE_FEATURE_FLAG_GNOSIS', 'false'));
it('returns POL for Gnosis (fallback)', async () => {
- const asset = getNativeAssetForChainId(gnosis.id);
+ const { getNativeAssetForChainId } = await import('../blockchain');
+ const asset = getNativeAssetForChainId(gnosis.id);
expect(asset.name).toBe('POL');
expect(asset.symbol).toBe('POL');
});
});
});Also applies to: 26-33, 41-47
🤖 Prompt for AI Agents
In src/utils/__tests__/blockchain.test.ts around lines 4-6 (and similarly for
26-33 and 41-47), the test mutates import.meta.env after the module (which
computes isGnosisEnabled at import time) has already been evaluated, so the
cached value is used and the test cannot toggle enabled/disabled; fix by
setting/stubbing import.meta.env before importing the module or by explicitly
re-importing the module fresh (e.g., using dynamic import or
jest.resetModules()/requireFresh) after you mutate import.meta.env so
isGnosisEnabled is evaluated with the desired env, or alternatively mock the
isGnosisEnabled export directly for each scenario.
| return isGnosisEnabled | ||
| ? `https://gnosisscan.io/${isAddress ? 'address' : 'tx'}/` | ||
| : ''; | ||
| case 56: |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Empty block explorer URL can ripple; verify call sites
Returning '' for chain 100 when disabled is fine if callers guard against falsy URLs. Otherwise, return undefined or avoid concatenation at usage sites.
Quick scan for risky concatenations:
🏁 Script executed:
#!/bin/bash
rg -nP -C2 'getBlockScan\([^)]*\)\s*(\+|`)' --type=ts --type=tsxLength of output: 27
🏁 Script executed:
#!/bin/bash
rg -nP -C2 'getBlockScan\([^)]*\)\s*(\+|`)' -g '*.ts' -g '*.tsx'Length of output: 0
🏁 Script executed:
#!/bin/bash
rg -n -C2 'getBlockScan\(' -g '*.ts' -g '*.tsx'Length of output: 3020
Prevent broken explorer links when getBlockScan returns empty
- src/components/BottomMenuModal/HistoryModal/TransactionsHistory.tsx:140
- src/components/BottomMenuModal/HistoryModal/TransactionInfo.tsx:213, 217, 237
- src/apps/pulse/components/Status/TxStatus.tsx:37
Either have getBlockScan return undefined/null when the explorer is disabled, or guard each ${getBlockScan(...)}${…} concatenation so you don’t render or open a malformed URL.
🤖 Prompt for AI Agents
In src/utils/blockchain.ts around lines 234–237, getBlockScan currently returns
an empty string when the explorer is disabled which leads to malformed URLs at
call sites; change it to return undefined (or null) instead of '' when disabled,
and then update all places that build URLs (e.g.,
src/components/BottomMenuModal/HistoryModal/TransactionsHistory.tsx line ~140,
TransactionInfo.tsx lines ~213/217/237, and
src/apps/pulse/components/Status/TxStatus.tsx line ~37) to guard the
concatenation by only constructing/opening the URL when getBlockScan(...) is
truthy (e.g., if (scanner) { const url = `${scanner}${path}`; ... }) so you
never render or open a broken URL.
| const STABLECOIN_ADDRESSES = Object.fromEntries( | ||
| Object.entries(allStablecoinAddresses).filter( | ||
| ([chainId]) => isGnosisEnabled || chainId !== '100' | ||
| ) | ||
| ) as Record<number, Set<string>>; | ||
|
|
There was a problem hiding this comment.
Case sensitivity bug in stablecoin detection
Sets contain mixed-case addresses but lookups use toLowerCase(), causing false negatives (e.g., BSC USDC/USDT). Normalize to lowercase when building the sets.
-const STABLECOIN_ADDRESSES = Object.fromEntries(
- Object.entries(allStablecoinAddresses).filter(
- ([chainId]) => isGnosisEnabled || chainId !== '100'
- )
-) as Record<number, Set<string>>;
+const STABLECOIN_ADDRESSES = Object.fromEntries(
+ Object.entries(allStablecoinAddresses)
+ .filter(([chainId]) => isGnosisEnabled || chainId !== '100')
+ .map(([chainId, set]) => [
+ Number(chainId),
+ new Set([...set].map((a) => a.toLowerCase())),
+ ])
+) as Record<number, Set<string>>;📝 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 STABLECOIN_ADDRESSES = Object.fromEntries( | |
| Object.entries(allStablecoinAddresses).filter( | |
| ([chainId]) => isGnosisEnabled || chainId !== '100' | |
| ) | |
| ) as Record<number, Set<string>>; | |
| const STABLECOIN_ADDRESSES = Object.fromEntries( | |
| Object.entries(allStablecoinAddresses) | |
| .filter(([chainId]) => isGnosisEnabled || chainId !== '100') | |
| .map(([chainId, set]) => [ | |
| Number(chainId), | |
| new Set([...set].map((a) => a.toLowerCase())), | |
| ]) | |
| ) as Record<number, Set<string>>; |
🤖 Prompt for AI Agents
In src/utils/blockchain.ts around lines 363 to 368, the stablecoin address sets
are built from allStablecoinAddresses but retain mixed-case values while lookups
use toLowerCase(), causing lookup failures; when constructing
STABLECOIN_ADDRESSES convert every address to lowercase (e.g., map each address
through .toLowerCase()) so the Record<number, Set<string>> contains lowercase
strings only, and keep the same Set type for membership checks to work
correctly.
Description
How Has This Been Tested?
Screenshots (if appropriate):
Types of changes
Summary by CodeRabbit
New Features
Bug Fixes
Tests