feat: integrate BOB (eip155:60808) as second-class citizen#11925
feat: integrate BOB (eip155:60808) as second-class citizen#11925gomesalexandre merged 55 commits intodevelopfrom
Conversation
…Relay bridge support Add support for Mantle (MNT native gas) including CAIP constants, chain adapter, plugin, feature flag, Relay swapper mapping, HDWallet support flags, CSP headers, asset generation script, and all required shared-file entries. Part of #11902
…lay bridge support Add support for Cronos (CRO native gas) including CAIP constants, chain adapter, plugin, feature flag, Relay swapper mapping, HDWallet support flags, CSP headers, asset generation script, and all required shared-file entries. Part of #11902
Add src/lib/utils/mantle.ts with getMantleTransactionStatus using eth_getTransactionReceipt via the Mantle RPC. Add KnownChainIds.MantleMainnet case to useSendActionSubscriber.tsx so Mantle transactions resolve in the action center.
Add src/lib/utils/cronos.ts with getCronosTransactionStatus using eth_getTransactionReceipt via the Cronos RPC. Add KnownChainIds.CronosMainnet case to useSendActionSubscriber.tsx so Cronos transactions resolve in the action center. Add CHAIN_REFERENCE.CronosMainnet case to relayTokenToAssetId.ts to prevent runtime crash on Relay swaps involving Cronos.
Address PR review feedback: - Add mantleChainId to getCoingeckoSupportedChainIds (feature-flagged) - Add mantle to ZERION_CHAINS array and ZERION_CHAINS_MAP - Across does not support Mantle, skipped
Address PR review feedback: - Add cronosChainId to getCoingeckoSupportedChainIds (feature-flagged) - Add cronos to ZERION_CHAINS array and ZERION_CHAINS_MAP - Across does not support Cronos, skipped
…ay swapper support
Adds full Unichain support including: - CAIP constants, types, and chain adapter - HDWallet support flags across all wallet implementations - Relay and Across swapper mappings - CoinGecko adapter with unichain platform - Zerion chain mapping - Feature flag, plugin, CSP headers - Portfolio, account, asset service, and market integrations - Asset generation scripts and related asset index (ETH-native) Part of #11902
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughThis PR adds comprehensive Bob EVM chain support across the entire application stack, including environment configuration, CAIP constants, chain adapters, wallet capabilities, blockchain clients, asset generation, feature flags, and transaction utilities. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
🚥 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)
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 |
The BOB adapter.json (eip155_60808) was created but not imported/exported from the generated index.ts, causing coingeckoToAssetIds to not return BOB. Also fix ethereum assetId ordering and add BOB to market-service test.
The Unichain adapter.json (eip155_130) was created but not imported/exported from the generated index.ts, causing coingeckoToAssetIds to not return Unichain.
The Sonic adapter.json (eip155_146) was created but not imported/exported from the generated index.ts, preventing CoinGecko mapping for Sonic tokens.
…tle-relay # Conflicts: # .env # .env.development # packages/caip/src/adapters/coingecko/generated/index.ts # packages/caip/src/adapters/coingecko/index.ts # packages/caip/src/adapters/coingecko/utils.test.ts # packages/caip/src/adapters/coingecko/utils.ts # packages/caip/src/constants.ts # packages/chain-adapters/src/evm/EvmBaseAdapter.ts # packages/chain-adapters/src/types.ts # packages/contracts/src/ethersProviderSingleton.ts # packages/contracts/src/viemClient.ts # packages/hdwallet-coinbase/src/coinbase.ts # packages/hdwallet-core/src/ethereum.ts # packages/hdwallet-core/src/wallet.ts # packages/hdwallet-gridplus/src/gridplus.ts # packages/hdwallet-keepkey/src/keepkey.ts # packages/hdwallet-ledger/src/ledger.ts # packages/hdwallet-metamask-multichain/src/shapeshift-multichain.ts # packages/hdwallet-native/src/ethereum.ts # packages/hdwallet-phantom/src/phantom.ts # packages/hdwallet-trezor/src/trezor.ts # packages/hdwallet-vultisig/src/vultisig.ts # packages/hdwallet-walletconnectv2/src/walletconnectV2.ts # packages/swapper/src/swappers/RelaySwapper/constant.ts # packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts # packages/types/src/base.ts # packages/types/src/zerion.ts # packages/utils/src/assetData/baseAssets.ts # packages/utils/src/assetData/getBaseAsset.ts # packages/utils/src/chainIdToFeeAssetId.ts # packages/utils/src/getAssetNamespaceFromChainId.ts # packages/utils/src/getChainShortName.ts # packages/utils/src/getNativeFeeAssetReference.ts # scripts/generateAssetData/coingecko.ts # scripts/generateAssetData/generateAssetData.ts # src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx # src/config.ts # src/constants/chains.ts # src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx # src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts # src/lib/account/evm.ts # src/lib/asset-service/service/AssetService.ts # src/lib/coingecko/utils.ts # src/pages/Markets/components/MarketsRow.tsx # src/state/slices/portfolioSlice/utils/index.ts # src/state/slices/preferencesSlice/preferencesSlice.ts # src/test/mocks/store.ts # src/vite-env.d.ts
Missing closing braces in 7 files where auto-resolve stripped them at mantle/next-entry boundaries. Also made generateChainRelatedAssetIndex self-contained (no import from generateRelatedAssetIndex to avoid module-scope ZERION_API_KEY check). Co-Authored-By: Claude Opus 4.6 <[email protected]>
77 Mantle assets added with relatedAssetKey cross-chain linking. Co-Authored-By: Claude Opus 4.6 <[email protected]>
…nos-relay # Conflicts: # .env # .env.development # headers/csps/index.ts # packages/caip/src/adapters/coingecko/generated/index.ts # packages/caip/src/adapters/coingecko/index.ts # packages/caip/src/adapters/coingecko/utils.test.ts # packages/caip/src/adapters/coingecko/utils.ts # packages/caip/src/constants.ts # packages/chain-adapters/src/evm/EvmBaseAdapter.ts # packages/chain-adapters/src/evm/index.ts # packages/chain-adapters/src/types.ts # packages/contracts/src/ethersProviderSingleton.ts # packages/contracts/src/viemClient.ts # packages/hdwallet-coinbase/src/coinbase.ts # packages/hdwallet-core/src/ethereum.ts # packages/hdwallet-core/src/wallet.ts # packages/hdwallet-gridplus/src/gridplus.ts # packages/hdwallet-keepkey/src/keepkey.ts # packages/hdwallet-ledger/src/ledger.ts # packages/hdwallet-metamask-multichain/src/shapeshift-multichain.ts # packages/hdwallet-native/src/ethereum.ts # packages/hdwallet-phantom/src/phantom.ts # packages/hdwallet-trezor/src/trezor.ts # packages/hdwallet-vultisig/src/vultisig.ts # packages/hdwallet-walletconnectv2/src/walletconnectV2.ts # packages/swapper/src/swappers/RelaySwapper/constant.ts # packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts # packages/types/src/base.ts # packages/types/src/zerion.ts # packages/utils/src/assetData/baseAssets.ts # packages/utils/src/assetData/getBaseAsset.ts # packages/utils/src/chainIdToFeeAssetId.ts # packages/utils/src/getAssetNamespaceFromChainId.ts # packages/utils/src/getChainShortName.ts # packages/utils/src/getNativeFeeAssetReference.ts # scripts/generateAssetData/coingecko.ts # scripts/generateAssetData/generateAssetData.ts # src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx # src/config.ts # src/constants/chains.ts # src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx # src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts # src/lib/account/evm.ts # src/lib/asset-service/service/AssetService.ts # src/lib/coingecko/utils.ts # src/pages/Markets/components/MarketsRow.tsx # src/state/slices/opportunitiesSlice/mappings.ts # src/state/slices/portfolioSlice/utils/index.ts # src/state/slices/preferencesSlice/preferencesSlice.ts # src/test/mocks/store.ts # src/vite-env.d.ts
…-relay # Conflicts: # src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
Co-Authored-By: Claude Opus 4.6 <[email protected]>
…-relay # Conflicts: # .beads/pr-context.jsonl # .beads/ss-dx5.8.json # .claude/contracts/second-class-evm-chain.md # .env # .env.development # packages/caip/src/adapters/coingecko/index.test.ts # packages/caip/src/adapters/coingecko/index.ts # packages/caip/src/adapters/coingecko/utils.test.ts # packages/caip/src/adapters/coingecko/utils.ts # packages/caip/src/constants.ts # packages/chain-adapters/src/evm/EvmBaseAdapter.ts # packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts # packages/chain-adapters/src/evm/index.ts # packages/chain-adapters/src/types.ts # packages/contracts/src/ethersProviderSingleton.ts # packages/contracts/src/viemClient.ts # packages/hdwallet-coinbase/src/coinbase.ts # packages/hdwallet-core/src/ethereum.ts # packages/hdwallet-core/src/wallet.ts # packages/hdwallet-gridplus/src/gridplus.ts # packages/hdwallet-keepkey/src/keepkey.ts # packages/hdwallet-ledger/src/ledger.ts # packages/hdwallet-metamask-multichain/src/shapeshift-multichain.ts # packages/hdwallet-native/src/ethereum.ts # packages/hdwallet-phantom/src/phantom.ts # packages/hdwallet-trezor/src/trezor.ts # packages/hdwallet-vultisig/src/vultisig.ts # packages/hdwallet-walletconnectv2/src/walletconnectV2.ts # packages/swapper/src/swappers/RelaySwapper/constant.ts # packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts # packages/types/src/base.ts # packages/types/src/zerion.ts # packages/utils/src/assetData/baseAssets.ts # packages/utils/src/assetData/getBaseAsset.ts # packages/utils/src/chainIdToFeeAssetId.ts # packages/utils/src/getAssetNamespaceFromChainId.ts # packages/utils/src/getChainShortName.ts # packages/utils/src/getNativeFeeAssetReference.ts # public/generated/asset-manifest.json # public/generated/asset-manifest.json.br # public/generated/asset-manifest.json.gz # public/generated/generatedAssetData.json # public/generated/generatedAssetData.json.br # public/generated/generatedAssetData.json.gz # public/generated/relatedAssetIndex.json # public/generated/relatedAssetIndex.json.br # public/generated/relatedAssetIndex.json.gz # scripts/generateAssetData/coingecko.ts # scripts/generateAssetData/generateAssetData.ts # scripts/generateAssetData/generateRelatedAssetIndex/generateChainRelatedAssetIndex.ts # scripts/generateAssetData/generateRelatedAssetIndex/generateRelatedAssetIndex.ts # src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx # src/config.ts # src/constants/chains.ts # src/context/PluginProvider/PluginProvider.tsx # src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx # src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts # src/lib/account/evm.ts # src/lib/asset-service/service/AssetService.ts # src/lib/coingecko/utils.ts # src/lib/market-service/coingecko/coingecko.test.ts # src/pages/Markets/components/MarketsRow.tsx # src/state/slices/opportunitiesSlice/mappings.ts # src/state/slices/portfolioSlice/utils/index.ts # src/state/slices/preferencesSlice/preferencesSlice.ts # src/test/mocks/store.ts # src/vite-env.d.ts
Co-Authored-By: Claude Opus 4.6 <[email protected]>
…etIndex Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/caip/src/constants.ts (1)
293-326:⚠️ Potential issue | 🟡 Minor
bobAssetIdmissing fromFEE_ASSET_IDSMost second-class EVM chains have their fee asset IDs in
FEE_ASSET_IDS(Monad, Mantle, Ink, MegaEth, Linea, Berachain, Scroll, Cronos, Sonic, Unichain), buthyperEvmAssetId,plasmaAssetId,katanaAssetId, and nowbobAssetIdare absent. The inline comment — "We should prob change this once we add more chains" — suggests these were intended to be included.If
FEE_ASSET_IDSis consulted anywhere to identify the native gas asset for a chain, BOB transactions may not be handled correctly.🛠️ Proposed fix
unichainAssetId, + bobAssetId, solAssetId,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/caip/src/constants.ts` around lines 293 - 326, FEE_ASSET_IDS is missing bobAssetId (and other second-class EVM assets like hyperEvmAssetId, plasmaAssetId, katanaAssetId) which can cause native gas detection to fail; update the exported FEE_ASSET_IDS array in constants.ts to include bobAssetId (and add the other missing asset id constants if intended) so that native fee handling covers BOB chains—locate the FEE_ASSET_IDS declaration and append bobAssetId to the list alongside the other second-class EVM asset id symbols.
🧹 Nitpick comments (5)
.env.development (1)
66-66: Optional: key ordering inconsistent withdotenv-linter
VITE_BOB_NODE_URLandVITE_FEATURE_BOB(line 116) trigger dotenv-linterUnorderedKeywarnings. The existing file uses logical grouping rather than strict alphabetical order so this is a pre-existing pattern, but if CI enforces the linter strictly these will need to move.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env.development at line 66, Reorder the environment keys to satisfy dotenv-linter's UnorderedKey rule by moving VITE_BOB_NODE_URL and VITE_FEATURE_BOB into their alphabetical positions among the other VITE_ variables (or adjust the linter config if grouping is intentional); locate the entries for VITE_BOB_NODE_URL and VITE_FEATURE_BOB and place them where they belong alphabetically with the rest of the VITE_ keys so CI no longer reports UnorderedKey warnings..env (1)
167-167:dotenv-linterflags unordered keys —VITE_BOB_NODE_URLfalls afterVITE_CRONOS_NODE_URL(B < C), andVITE_FEATURE_BOBfalls afterVITE_FEATURE_CETUS_SWAP(B < C). The project pattern places newly added chains at the end of each section rather than inserting alphabetically, so this is consistent with how all other recent second-class chains (Monad, Plasma, Katana, Unichain, etc.) are positioned.Also applies to: 324-324
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env at line 167, The dotenv-linter complaint is about key ordering for VITE_BOB_NODE_URL and VITE_FEATURE_BOB; to match project convention (append new chains to the end of each section), move VITE_BOB_NODE_URL and VITE_FEATURE_BOB out of their current alphabetical positions and place each at the end of their respective environment-variable sections so they follow the positioning of other second-class chains (e.g., Monad, Plasma, Katana, Unichain).src/plugins/bob/index.tsx (1)
25-35:fromAssetIdis called twice per asset — once in.filter()and again in.map().♻️ Optional: destructure all needed fields in a single `.reduce()` pass
- return assetService.assets - .filter(asset => { - const { chainId, assetNamespace } = fromAssetId(asset.assetId) - return chainId === bobChainId && assetNamespace === 'erc20' - }) - .map(asset => ({ - assetId: asset.assetId, - contractAddress: fromAssetId(asset.assetId).assetReference, - symbol: asset.symbol, - name: asset.name, - precision: asset.precision, - })) + return assetService.assets.reduce<ReturnType<typeof getKnownTokens>>( + (acc, asset) => { + const { chainId, assetNamespace, assetReference } = fromAssetId(asset.assetId) + if (chainId !== bobChainId || assetNamespace !== 'erc20') return acc + acc.push({ + assetId: asset.assetId, + contractAddress: assetReference, + symbol: asset.symbol, + name: asset.name, + precision: asset.precision, + }) + return acc + }, + [], + )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/plugins/bob/index.tsx` around lines 25 - 35, The code calls fromAssetId(asset.assetId) twice per item (once in the .filter and again in the .map) which is wasteful; change the pipeline to call fromAssetId once and reuse its result—e.g., replace the current .filter/.map chain with a single .reduce or map-after-filter that first extracts const { chainId, assetNamespace, assetReference } = fromAssetId(asset.assetId) and then checks chainId === bobChainId && assetNamespace === 'erc20' before returning the mapped object (using assetReference for contractAddress); ensure references to fromAssetId, bobChainId, and assetReference are updated accordingly so parsing occurs only once per asset.src/lib/utils/bob.ts (2)
20-22: Consider a module-level provider to avoid connection overhead on each poll cycle.A new
JsonRpcProvideris instantiated on every call. SincegetBobTransactionStatusis likely called repeatedly in a polling loop, a module-level (or memoized) provider keyed onnodeUrlwould avoid redundant HTTP connection setup. The codebase already has a singleton provider pattern (packages/contracts/src/ethersProviderSingleton.ts) that could serve as a reference.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/utils/bob.ts` around lines 20 - 22, The function getBobTransactionStatus currently creates a new JsonRpcProvider for each invocation (const provider = new JsonRpcProvider(nodeUrl...)), causing connection overhead; refactor to use a module-level or memoized provider keyed by nodeUrl (or reuse the existing ethersProviderSingleton pattern) so repeated calls reuse the same provider instance instead of instantiating one per poll cycle; replace the local provider creation in getBobTransactionStatus with a lookup/get-or-create call to the shared provider store and ensure the options (staticNetwork: true) are applied when creating the cached instance.
39-41: Use structured logger instead ofconsole.error.
console.errorviolates the project's logging guideline. As per coding guidelines (ALWAYS log errors for debugging using structured logging with relevant context and error metadata).♻️ Proposed fix
+import { logger } from 'lib/logger' + +const moduleLogger = logger.child({ namespace: ['lib', 'utils', 'bob'] }) + } catch (error) { - console.error('[BOB] Error getting transaction status:', error) + moduleLogger.error(error, '[BOB] Error getting transaction status') return TxStatus.Unknown }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/utils/bob.ts` around lines 39 - 41, Replace the console.error call in the catch block that currently logs "[BOB] Error getting transaction status:" and returns TxStatus.Unknown with the project's structured logger; capture and pass the error object and additional context to the logger (e.g., logger.error or processLogger.error) so the message, error metadata, and any relevant transaction identifiers are included, then return TxStatus.Unknown as before. Locate the catch in src/lib/utils/bob.ts where the string "[BOB] Error getting transaction status:" is emitted and update it to use the structured logger API consistent with other modules.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@packages/caip/src/constants.ts`:
- Around line 293-326: FEE_ASSET_IDS is missing bobAssetId (and other
second-class EVM assets like hyperEvmAssetId, plasmaAssetId, katanaAssetId)
which can cause native gas detection to fail; update the exported FEE_ASSET_IDS
array in constants.ts to include bobAssetId (and add the other missing asset id
constants if intended) so that native fee handling covers BOB chains—locate the
FEE_ASSET_IDS declaration and append bobAssetId to the list alongside the other
second-class EVM asset id symbols.
---
Nitpick comments:
In @.env:
- Line 167: The dotenv-linter complaint is about key ordering for
VITE_BOB_NODE_URL and VITE_FEATURE_BOB; to match project convention (append new
chains to the end of each section), move VITE_BOB_NODE_URL and VITE_FEATURE_BOB
out of their current alphabetical positions and place each at the end of their
respective environment-variable sections so they follow the positioning of other
second-class chains (e.g., Monad, Plasma, Katana, Unichain).
In @.env.development:
- Line 66: Reorder the environment keys to satisfy dotenv-linter's UnorderedKey
rule by moving VITE_BOB_NODE_URL and VITE_FEATURE_BOB into their alphabetical
positions among the other VITE_ variables (or adjust the linter config if
grouping is intentional); locate the entries for VITE_BOB_NODE_URL and
VITE_FEATURE_BOB and place them where they belong alphabetically with the rest
of the VITE_ keys so CI no longer reports UnorderedKey warnings.
In `@src/lib/utils/bob.ts`:
- Around line 20-22: The function getBobTransactionStatus currently creates a
new JsonRpcProvider for each invocation (const provider = new
JsonRpcProvider(nodeUrl...)), causing connection overhead; refactor to use a
module-level or memoized provider keyed by nodeUrl (or reuse the existing
ethersProviderSingleton pattern) so repeated calls reuse the same provider
instance instead of instantiating one per poll cycle; replace the local provider
creation in getBobTransactionStatus with a lookup/get-or-create call to the
shared provider store and ensure the options (staticNetwork: true) are applied
when creating the cached instance.
- Around line 39-41: Replace the console.error call in the catch block that
currently logs "[BOB] Error getting transaction status:" and returns
TxStatus.Unknown with the project's structured logger; capture and pass the
error object and additional context to the logger (e.g., logger.error or
processLogger.error) so the message, error metadata, and any relevant
transaction identifiers are included, then return TxStatus.Unknown as before.
Locate the catch in src/lib/utils/bob.ts where the string "[BOB] Error getting
transaction status:" is emitted and update it to use the structured logger API
consistent with other modules.
In `@src/plugins/bob/index.tsx`:
- Around line 25-35: The code calls fromAssetId(asset.assetId) twice per item
(once in the .filter and again in the .map) which is wasteful; change the
pipeline to call fromAssetId once and reuse its result—e.g., replace the current
.filter/.map chain with a single .reduce or map-after-filter that first extracts
const { chainId, assetNamespace, assetReference } = fromAssetId(asset.assetId)
and then checks chainId === bobChainId && assetNamespace === 'erc20' before
returning the mapped object (using assetReference for contractAddress); ensure
references to fromAssetId, bobChainId, and assetReference are updated
accordingly so parsing occurs only once per asset.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
gomesalexandre
left a comment
There was a problem hiding this comment.
lgtm - all CI green, contract review done.
prior testing confirmed on BOB (native ETH balance, relay bridge quotes, chain selector). will re-verify on Soneium as final chain in the pipeline.
merge conflicts with develop (cronos+sonic+unichain) resolved cleanly - migration 298 added, related asset index updated with bobAssetId in ethAssetId group, market service test counts bumped (flatten=11, rate limited=10).
Description
Integrates BOB (eip155:60808) as a second-class citizen chain in ShapeShift Web via Relay.link.
This is PR 5 of 17 in a sequential chain integration series. These PRs must be reviewed and merged in order, as each builds on the previous one (stacked branches).
PR merge order:
BOB is an EVM L2 with ETH as its native gas token. This integration adds full support including:
bob-network, maps toethereum)VITE_FEATURE_BOB) gated behind second-class citizen configIssue (if applicable)
Part of #11902
Risk
Low risk - feature-flagged second-class chain integration following established patterns (identical to Scroll, Ink, Mantle, Cronos, Berachain, Linea, Sonic, Unichain integrations).
No existing protocols affected. New chain only accessible when feature flag is enabled.
Testing
Engineering
VITE_FEATURE_BOB=truein.env.developmentyarn type-check- passesyarn lint- passesOperations
Screenshots (if applicable)
N/A - chain integration following established patterns
Summary by CodeRabbit
New Features
Chores