feat(chains): add Robinhood Chain (EVM 4663) as second-class chain - #12497
feat(chains): add Robinhood Chain (EVM 4663) as second-class chain#12497swdiscordia wants to merge 4 commits into
Conversation
Robinhood Chain launched its public mainnet 2026-07-01 with Relay, 0x, and Across already routing it live in production. Wires it in as a second-class EVM chain per .claude/contracts/second-class-evm-chain.md, feature-flagged off in production (VITE_FEATURE_ROBINHOOD). Live-tested with a real test wallet: real swaps executed and independently verified on-chain in both directions via Relay (mainnet ETH <-> Robinhood ETH).
📝 WalkthroughWalkthroughAdds Robinhood mainnet support across CAIP identifiers, assets, RPC clients, chain adapters, wallet capability detection, swappers, feature flags, plugins, CoinGecko integration, and application state. ChangesRobinhood chain integration
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant FeatureFlags
participant PluginProvider
participant RobinhoodChainAdapter
participant AssetService
FeatureFlags->>PluginProvider: enable Robinhood
PluginProvider->>RobinhoodChainAdapter: initialize adapter
RobinhoodChainAdapter->>AssetService: load Robinhood ERC20 assets
AssetService-->>RobinhoodChainAdapter: return token metadata
RobinhoodChainAdapter-->>PluginProvider: register adapter
Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/hdwallet-core/src/wallet.ts (1)
280-282: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAvoid
anyin the new type guard.Use a typed property check and return an explicit boolean instead of
(wallet as any).Proposed fix
export function supportsRobinhood(wallet: HDWallet): wallet is ETHWallet { - return isObject(wallet) && (wallet as any)._supportsRobinhood + return isObject(wallet) && '_supportsRobinhood' in wallet && wallet._supportsRobinhood === true }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/hdwallet-core/src/wallet.ts` around lines 280 - 282, Update supportsRobinhood to avoid the any cast by using a typed property check for _supportsRobinhood, and return an explicit boolean while preserving the existing ETHWallet type-guard behavior.Source: Coding guidelines
packages/chain-adapters/src/evm/robinhood/RobinhoodChainAdapter.ts (1)
40-46: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd explicit return types.
To comply with coding guidelines, please add explicit return types to these methods.
♻️ Proposed refactor
- getDisplayName() { + getDisplayName(): string { return ChainAdapterDisplayName.Robinhood } - getName() { + getName(): string { return 'Robinhood' }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/chain-adapters/src/evm/robinhood/RobinhoodChainAdapter.ts` around lines 40 - 46, Add explicit return type annotations to the RobinhoodChainAdapter methods getDisplayName and getName, using the types corresponding to their returned enum value and string while preserving the existing return values.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/hdwallet-metamask-multichain/src/native-multichain.ts`:
- Line 307: Update ethSupportsNetwork in
packages/hdwallet-metamask-multichain/src/native-multichain.ts and
packages/hdwallet-metamask-multichain/src/shapeshift-multichain.ts to allow
chain ID 4663 alongside 1, keeping both MetaMask variants’ Robinhood support
declarations synchronized with their network allowlists.
---
Nitpick comments:
In `@packages/chain-adapters/src/evm/robinhood/RobinhoodChainAdapter.ts`:
- Around line 40-46: Add explicit return type annotations to the
RobinhoodChainAdapter methods getDisplayName and getName, using the types
corresponding to their returned enum value and string while preserving the
existing return values.
In `@packages/hdwallet-core/src/wallet.ts`:
- Around line 280-282: Update supportsRobinhood to avoid the any cast by using a
typed property check for _supportsRobinhood, and return an explicit boolean
while preserving the existing ETHWallet type-guard behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 81b00475-3b70-4ab6-851a-dd219d4f3488
⛔ Files ignored due to path filters (11)
packages/caip/src/adapters/coingecko/generated/eip155_4663/adapter.jsonis excluded by!**/generated/**packages/caip/src/adapters/coingecko/generated/index.tsis excluded by!**/generated/**public/generated/asset-manifest.jsonis excluded by!**/generated/**public/generated/asset-manifest.json.bris excluded by!**/generated/**public/generated/asset-manifest.json.gzis excluded by!**/*.gz,!**/generated/**public/generated/generatedAssetData.jsonis excluded by!**/generated/**public/generated/generatedAssetData.json.bris excluded by!**/generated/**public/generated/generatedAssetData.json.gzis excluded by!**/*.gz,!**/generated/**public/generated/relatedAssetIndex.jsonis excluded by!**/generated/**public/generated/relatedAssetIndex.json.bris excluded by!**/generated/**public/generated/relatedAssetIndex.json.gzis excluded by!**/*.gz,!**/generated/**
📒 Files selected for processing (69)
.env.env.developmentchains/robinhood.jsonheaders/csps/chains/robinhood.tsheaders/csps/index.tspackages/caip/src/adapters/coingecko/index.test.tspackages/caip/src/adapters/coingecko/index.tspackages/caip/src/adapters/coingecko/utils.test.tspackages/caip/src/adapters/coingecko/utils.tspackages/caip/src/constants.tspackages/chain-adapters/src/evm/EvmBaseAdapter.tspackages/chain-adapters/src/evm/SecondClassEvmAdapter.tspackages/chain-adapters/src/evm/index.tspackages/chain-adapters/src/evm/robinhood/RobinhoodChainAdapter.tspackages/chain-adapters/src/evm/robinhood/index.tspackages/chain-adapters/src/types.tspackages/contracts/src/ethersProviderSingleton.tspackages/contracts/src/publicRpcUrls.tspackages/contracts/src/viemClient.tspackages/hdwallet-coinbase/src/coinbase.tspackages/hdwallet-core/src/ethereum.tspackages/hdwallet-core/src/wallet.tspackages/hdwallet-gridplus/src/gridplus.tspackages/hdwallet-keepkey/src/keepkey.tspackages/hdwallet-ledger/src/ledger.tspackages/hdwallet-metamask-multichain/src/native-multichain.tspackages/hdwallet-metamask-multichain/src/shapeshift-multichain.tspackages/hdwallet-native/src/ethereum.tspackages/hdwallet-phantom/src/phantom.tspackages/hdwallet-trezor/src/trezor.tspackages/hdwallet-vultisig/src/vultisig.tspackages/hdwallet-walletconnectv2/src/walletconnectV2.tspackages/swapper/src/swappers/AcrossSwapper/constant.tspackages/swapper/src/swappers/RelaySwapper/constant.tspackages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.tspackages/swapper/src/swappers/ZrxSwapper/types.tspackages/swapper/src/swappers/ZrxSwapper/utils/constants.tspackages/swapper/src/swappers/ZrxSwapper/utils/helpers/helpers.tspackages/types/src/base.tspackages/utils/src/assetData/baseAssets.tspackages/utils/src/assetData/getBaseAsset.tspackages/utils/src/chainIdToFeeAssetId.tspackages/utils/src/getAssetNamespaceFromChainId.tspackages/utils/src/getChainShortName.tspackages/utils/src/getNativeFeeAssetReference.tsscripts/generateAssetData/coingecko.tsscripts/generateAssetData/generateAssetData.tsscripts/generateAssetData/generateRelatedAssetIndex/generateChainRelatedAssetIndex.tsscripts/generateAssetData/generateRelatedAssetIndex/generateRelatedAssetIndex.tsscripts/generateAssetData/robinhood/index.tssrc/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsxsrc/config.tssrc/constants/chains.tssrc/context/PluginProvider/PluginProvider.tsxsrc/context/WalletProvider/WalletConnectV2/config.tssrc/hooks/useWalletSupportsChain/useWalletSupportsChain.tssrc/lib/account/evm.tssrc/lib/asset-service/service/AssetService.tssrc/lib/coingecko/utils.tssrc/lib/market-service/coingecko/coingecko.test.tssrc/pages/Markets/components/MarketsRow.tsxsrc/plugins/activePlugins.tssrc/plugins/robinhood/index.tsxsrc/state/migrations/index.tssrc/state/slices/opportunitiesSlice/mappings.tssrc/state/slices/portfolioSlice/utils/index.tssrc/state/slices/preferencesSlice/preferencesSlice.tssrc/test/mocks/store.tssrc/vite-env.d.ts
|
Checked the two nitpick suggestions against existing precedent before deciding whether to apply them:
Both are reasonable general code-quality suggestions, just not something this PR should fix in isolation without also touching ~30 other files for consistency - happy to do that as a separate cleanup if the team wants it. |
…PC fanout Multicall3 is deployed at the canonical address on Robinhood Chain (verified via eth_getCode) but wasn't declared in the local viem defineChain(), so every token balance read silently fell back to one RPC call per token against a rate-limited public endpoint. Verified live: before this fix each account load logged "[Robinhood] Multicall failed, falling back to individual calls"; after, it doesn't, and the same real USDG balance still displays correctly.
…15-robinhood-chain # Conflicts: # 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.br # public/generated/relatedAssetIndex.json.gz # src/state/migrations/index.ts
301 assets now (up from 283), reflects both upstream's asset updates across the merged 86 commits and Robinhood's own token list refresh.
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)
.env (1)
236-236: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winRotate/remove the browser-exposed API keys.
VITE_TRON_GRID_API_KEYandVITE_BOB_GATEWAY_API_KEYare committed in.envand forwarded into the client config, so they should be treated as public. Revoke/rotate them and move any sensitive authorization server-side; if these are meant to be public API keys, lock them down with origin/quota limits instead.
.env#L236-L236:VITE_TRON_GRID_API_KEY.env#L375-L375:VITE_BOB_GATEWAY_API_KEY🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.env at line 236, Remove the exposed VITE_TRON_GRID_API_KEY at .env:236-236 and VITE_BOB_GATEWAY_API_KEY at .env:375-375, revoke or rotate both credentials, and move sensitive authorization server-side; if either must remain public, restrict it with origin and quota limits.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In @.env:
- Line 236: Remove the exposed VITE_TRON_GRID_API_KEY at .env:236-236 and
VITE_BOB_GATEWAY_API_KEY at .env:375-375, revoke or rotate both credentials, and
move sensitive authorization server-side; if either must remain public, restrict
it with origin and quota limits.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: aed427ff-3595-472b-8a2e-9b1d82f3f79b
⛔ Files ignored due to path filters (3)
public/generated/asset-manifest.jsonis excluded by!**/generated/**public/generated/asset-manifest.json.bris excluded by!**/generated/**public/generated/asset-manifest.json.gzis excluded by!**/*.gz,!**/generated/**
📒 Files selected for processing (10)
.env.env.developmentheaders/csps/index.tspackages/caip/src/adapters/coingecko/index.test.tspackages/caip/src/constants.tspackages/chain-adapters/src/evm/EvmBaseAdapter.tspackages/chain-adapters/src/evm/SecondClassEvmAdapter.tspackages/hdwallet-core/src/ethereum.tspackages/swapper/src/swappers/RelaySwapper/constant.tspackages/utils/src/assetData/baseAssets.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- headers/csps/index.ts
- packages/caip/src/adapters/coingecko/index.test.ts
- packages/swapper/src/swappers/RelaySwapper/constant.ts
- packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
- packages/utils/src/assetData/baseAssets.ts
- packages/caip/src/constants.ts
- packages/chain-adapters/src/evm/EvmBaseAdapter.ts
|
Checked this before doing anything: both Not something this PR should touch: rotating/removing third-party API keys is unrelated to a chain integration and outside what I have context or authority to do here. Flagging for the team to triage separately if it's actually a live concern. |
Description
Adds Robinhood Chain (EVM chain id 4663, an Arbitrum Orbit rollup settling on Ethereum L1, launched 2026-07-01) as a second-class EVM chain, following
.claude/contracts/second-class-evm-chain.md.Wires up the three swappers that already route this chain live in production:
Includes the full second-class chain checklist: CAIP constants,
KnownChainIdsentry, chain adapter (packages/chain-adapters/src/evm/robinhood/), HDWallet support across all wallet packages (native, Ledger, Trezor, Phantom, MetaMask multichain, WalletConnect V2, Coinbase, KeepKey, GridPlus, Vultisig), viem client wiring (Robinhood isn't in the pinned viem version yet, so it's defined locally viadefineChain(), same pattern as MegaETH/Ethereal, with Multicall3 explicitly wired since it's deployed at the canonical address on this chain), plugin registration (src/plugins/robinhood/), CSP headers, and generated asset data (283 assets, no native/ERC20 duplicate).New feature flag
VITE_FEATURE_ROBINHOOD:falsein.env(off in production),truein.env.development.Known non-blocking follow-ups, left for a separate PR:
Issue (if applicable)
Traces back to Linear SS-5715 (engineering) / BIZ-34 (business). No corresponding GitHub issue to close.
Risk
High risk — this PR should carry the "high risk" label and requires 2 approvals before merge.
This introduces a brand new on-chain transaction type: a new chain means new send and swap transaction paths (build/sign/broadcast) that did not exist before, exercised through the chain adapter and all HDWallet implementations.
Protocols, transaction types, wallets, and contract interactions affected:
supportsRobinhood()/_supportsRobinhood— all wallet types are technically touched by the interface change even though only EVM-capable wallets will actually sign on this chainNo existing chain's send/swap/bridge logic is modified; all changes are additive (new chain id branch in each integration point).
Testing
Engineering
pnpm run build:packages— 0 TS errorspnpm run lint --fix— 0 errorspnpm run type-check— 0 errorspnpm run generate:chain eip155:4663— 283 assets generated, no native/ERC20 duplicate (chain is standard ETH-native)pnpm exec viteston the CoinGecko adapter + market-service test suites — all green after regenerating thepackages/caipCoinGecko adapter data for this chainReal, live end-to-end testing was performed with a funded test wallet (not just unit tests, not just trusting the app's own UI — every transaction was independently verified on-chain):
0x6b63fe6e5fc40e0bb80532160bb2f045c76da9538a9a76018095d8165ac73fdddepositNativecall to Relay's Depository contract on Robinhood Chain, plus an independent mainnet balance check (before/after) via public RPC — not just the app's success toast0x9a536c13073f83ec5c0ba86ac6878914b6d84f4db538667a5658ce91f12ed088(WETH wrap → Uniswap V3 → USDG, token transfer log confirms the exact amount). The wallet's own balance display picked it up correctly afterward (Balance: 0.057219 USDG), confirming ERC-20 token balance tracking works on this chain, not just the native asset.eth_getCode) wasn't wired into the local viem chain definition, so every token balance read was silently falling back to one RPC call per token against a rate-limited public endpoint (logged as"[Robinhood] Multicall failed, falling back to individual calls"). Fixed by declaringcontracts.multicall3in the chain definition — verified live that the warning is now gone and the same real USDG balance still displays correctly.swapFeeRecipientconfig gap in the 0x price request — reproduced this exact same error on mainnet (chain 1) with an equivalent manually-constructed request, confirming it's a pre-existing, chain-agnostic local dev environment limitation, not a Robinhood-specific regressionOperations
VITE_FEATURE_ROBINHOODisfalsein production and onlytruein dev. To manually verify in a preview environment: flip the flag, confirm Robinhood Chain appears in the network/chain selector, confirm ETH balance loads for a Robinhood Chain account, and run a small test swap in each direction (mainnet ETH ↔ Robinhood ETH) via Relay, checking the resulting tx on https://robinhoodchain.blockscout.com.Screenshots (if applicable)
Robinhood Chain selected, native ETH balance loading correctly

Live quote, mainnet ETH → Robinhood ETH via Relay

Two independent live quotes for the same trade (Relay + Across)

Swap complete — real transaction, confirmed by the app and independently on Blockscout

Reverse direction confirm screen, Robinhood ETH → mainnet ETH via Relay

Final state: both balances correctly updated after both real swaps

Real ERC-20 token balance (USDG) correctly displayed after a real same-chain swap

Summary by CodeRabbit