feat: integrate Berachain (chainId 80094) as second-class EVM chain#11918
feat: integrate Berachain (chainId 80094) as second-class EVM chain#11918gomesalexandre merged 10 commits intodevelopfrom
Conversation
…fix steps Add Step 5.6 documenting the ETH related asset index addition needed for chains where ETH is the native gas token. Add Step 7.0 documenting common test fixes required after chain integration (parseData, coingeckoToAssetIds, targetNetwork).
Add Berachain mainnet support via Relay bridge swapper: - CAIP identifiers, chain adapter, HDWallet support (all 12 wallets) - Viem/ethers clients, CSP headers, feature flag - CoinGecko adapter (berachain-bera), base asset (BERA) - Plugin registration, account derivation, portfolio utils - Relay swapper chain mapping and token mapping - TX status polling via eth_getTransactionReceipt Asset generation scripts not yet run (requires Zerion API key).
📝 WalkthroughWalkthroughThis PR implements comprehensive support for Berachain (chainID 80094), a new EVM chain, across the ShapeShift web application. Changes include environment configuration, CAIP constants, chain adapters, wallet support declarations, asset definitions, CoinGecko integration, viem clients, plugin registration, feature flagging, state management, and utilities for transaction status handling. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes The changes span 50+ files across multiple package boundaries with heterogeneous modifications: CAIP constants and types, chain-adapter architecture, hdwallet flag declarations (repetitive but distinct per wallet), asset generation pipelines, viem/ethers client wiring, feature-flag gating logic, transaction-status utilities, and state management. While individual changes are straightforward (mostly following established patterns), the breadth, density of chain-integration touch points, new adapter implementation, and varying logical branches (feature flags, wallet support checks, asset filtering) demand careful cross-file validation and understanding of the integration architecture. Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
Address PR review feedback: - Add berachainChainId to getCoingeckoSupportedChainIds (feature-flagged) - Add berachain to ZERION_CHAINS array and ZERION_CHAINS_MAP - Across does not support Berachain, skipped
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d trailing slash Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gomesalexandre
left a comment
There was a problem hiding this comment.
Tested most flows and everything looks good — happy with the integration overall 👍
One issue found: Relay cross-chain swaps to Berachain (e.g. ETH → BERA) are missing execution price in the action center and BERA receive in tx history. Root cause: Berachain's public RPC doesn't support debug_traceTransaction, so internal transaction tracing fails silently, making native BERA receives via internal calls invisible.
Jam: https://jam.dev/c/11f18a1b-7950-4017-a1a3-d5fafa3df9d4
Working on a fix — parsing WBERA Withdrawal events as a fallback for native receive detection on Berachain.
…ilable Berachain's public RPC doesn't support debug_traceTransaction, causing SecondClassEvmAdapter.parseTx() to miss native BERA receives via internal calls (e.g. cross-chain Relay fills). This adds a Berachain-specific fallback that parses WBERA burn events (ERC20 Transfer to zero address) from the tx receipt as synthetic internal transactions, enabling correct execution price display and tx history entries. Also fixes React Query "data cannot be undefined" warning in useActualBuyAmountCryptoPrecision by returning null instead of undefined. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gomesalexandre
left a comment
There was a problem hiding this comment.
Cross-chain swaps to BERA are now fixed — native BERA receive detection works via WBERA burn event fallback when debug_traceTransaction is unavailable on the public RPC. Execution price and tx history entries display correctly.
Also confirmed cross-chain swaps from BERA are happy (tx history + execution price).
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
.beads/ss-dx5.5.json (1)
7-7:statusand checklist innotesdon't reflect actual work completed in this PR.The task
statusremains"open"and all checklist items innotesare still unchecked ([ ]), but this PR implements the majority of them (chain-adapters, caip, feature-flag, plugin, env-config, Relay constant/token mappings). If the beads system uses this file for progress tracking, both thestatusand the checklist markers should be updated to reflect what's done vs. what's explicitly deferred (generated asset data, color-map).📋 Suggested status and checklist update
- "status": "open", + "status": "in_progress",And in
notes, mark completed items with[x]:Checklist: [x] chain-adapters [x] caip [ ] asset-service [x] feature-flag [x] plugin [x] env-config [ ] icon/logo [x] fee-asset-config --- RELAY ACTIVATION --- [x] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts [x] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.tsAlso applies to: 6-6
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.beads/ss-dx5.5.json at line 7, Update the "status" value in the JSON from "open" to "closed" (or an appropriate completed state) and edit the "notes" checklist so items implemented in this PR are checked ([x]) while leaving deferred items unchecked; specifically mark chain-adapters, caip, feature-flag, plugin, env-config, fee-asset-config and the two RELAY ACTIVATION lines (Add to chainIdToRelayChainId and Add native asset case) as completed [x], and leave asset-service and icon/logo unchecked. Ensure the "notes" string preserves formatting and only the checklist markers are changed..env.development (1)
67-67:dotenv-linterordering warnings — bothVITE_BERACHAIN_NODE_URL(line 67) andVITE_FEATURE_BERACHAIN(line 102) are flagged asUnorderedKey(should precedeVITE_BNBSMARTCHAIN_NODE_URLandVITE_FEATURE_CETUS_SWAPrespectively in strict alphabetical order). Both values are functionally correct; the ordering is consistent with how other recent second-class chains (MegaEth, Ink) were added in-place at the bottom of their sections rather than re-sorted alphabetically. Resolve only if you want to keep the linter clean.🔧 Proposed fix: move keys to their alphabetical positions
VITE_BASE_NODE_URL=... +VITE_BERACHAIN_NODE_URL=https://rpc.berachain.com VITE_BNBSMARTCHAIN_NODE_URL=... ... -VITE_MEGAETH_NODE_URL=... -VITE_BERACHAIN_NODE_URL=https://rpc.berachain.com -VITE_SCROLL_NODE_URL=... +VITE_MEGAETH_NODE_URL=... +VITE_SCROLL_NODE_URL=...+VITE_FEATURE_BERACHAIN=true VITE_FEATURE_CETUS_SWAP=true ... -VITE_FEATURE_MEGAETH=true -VITE_FEATURE_BERACHAIN=true -VITE_FEATURE_SCROLL=true +VITE_FEATURE_MEGAETH=true +VITE_FEATURE_SCROLL=trueAlso applies to: 102-102
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env.development at line 67, Lint flags indicate two .env keys are out of alphabetical order: VITE_BERACHAIN_NODE_URL and VITE_FEATURE_BERACHAIN; to fix, move VITE_BERACHAIN_NODE_URL so it appears alphabetically before VITE_BNBSMARTCHAIN_NODE_URL and move VITE_FEATURE_BERACHAIN so it appears alphabetically before VITE_FEATURE_CETUS_SWAP (or reorder the surrounding section alphabetically), ensuring the variable names and their values remain unchanged.src/vite-env.d.ts (1)
119-120: Minor grouping inconsistency –VITE_FEATURE_BERACHAINis a feature flag but is placed in the "URLs and API keys from base .env" section, whereas the comparableVITE_FEATURE_INK(Line 64) lives in the "Feature flags – present in all envs" section. Functionally harmless (the interface is flat), but for consistency both entries could move up to the feature-flags block alongsideVITE_INK_NODE_URL.♻️ Suggested placement (move to feature flags section)
readonly VITE_FEATURE_INK: string readonly VITE_INK_NODE_URL: string + readonly VITE_BERACHAIN_NODE_URL: string + readonly VITE_FEATURE_BERACHAIN: string // URLs and API keys from base .env (always defined) ... readonly VITE_NEAR_INTENTS_API_KEY: string readonly VITE_FEATURE_NEAR_INTENTS_SWAP: string - readonly VITE_BERACHAIN_NODE_URL: string - readonly VITE_FEATURE_BERACHAIN: string readonly VITE_RELAY_API_URL: string🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/vite-env.d.ts` around lines 119 - 120, The VITE_FEATURE_BERACHAIN declaration is grouped under "URLs and API keys" but should be with other feature flags for consistency; move the line declaring readonly VITE_FEATURE_BERACHAIN into the "Feature flags – present in all envs" block alongside VITE_FEATURE_INK and VITE_INK_NODE_URL, updating the surrounding comment blocks so feature flags are grouped together while leaving the interface flat and unchanged otherwise.src/plugins/berachain/index.tsx (1)
25-35:fromAssetIdcalled twice per asset — minor optional refactor.
fromAssetId(asset.assetId)is parsed in thefiltercallback (Line 26) and then parsed again inmapforcontractAddress(Line 31). Combining into a single pass withreduceor capturing the parsed result avoids the redundant parse.♻️ Proposed refactor (single-pass)
- return assetService.assets - .filter(asset => { - const { chainId, assetNamespace } = fromAssetId(asset.assetId) - return chainId === berachainChainId && 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 === berachainChainId && assetNamespace === 'erc20') { + 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/berachain/index.tsx` around lines 25 - 35, The code calls fromAssetId(asset.assetId) twice — once in the filter and again in the map — causing redundant parsing; change the pipeline to parse once per asset (e.g., replace the filter+map with a single pass that extracts parsed = fromAssetId(asset.assetId) and uses parsed.chainId/parsed.assetNamespace to filter and parsed.assetReference for contractAddress) so functions like fromAssetId, filter, and map operate on the parsed result for each asset rather than re-parsing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.claude/skills/chain-integration/SKILL.md:
- Around line 1797-1801: Add a blank line immediately before the Markdown table
that begins with "| Native Token | CoinGecko ID | Update index.test.ts? | Update
utils.test.ts? |" in .claude/skills/chain-integration/SKILL.md to satisfy MD058;
locate the table header and insert a single empty line above it so the table is
separated from the preceding paragraph or content.
- Line 1766: The markdown fenced code block on SKILL.md is missing a language
specifier (MD040); update the triple-backtick fence that contains the TypeScript
compiler message (the block starting with "error TS2339: Property
'eip155:XXX'...") to include a language tag such as ```ts or ```text so the
block becomes ```ts (or ```text) followed by the error lines and a closing ```,
which will resolve the lint error and enable proper syntax highlighting.
In `@packages/hdwallet-trezor/src/trezor.ts`:
- Line 302: The repo shows inconsistent presence of the _supportsBerachain flag
across wallet implementations; add a readonly _supportsBerachain = true property
to each wallet class that otherwise supports EVM signing (e.g., KeepKeyHDWallet,
LedgerHDWallet and their subpackage variants, NativeHDWallet/NativeVault,
TrezorConnectWallet, Keplr/Seeker implementations) so they match the pattern
used in TrezorHDWallet and other EVM second-class chains; update the class
definitions where missing, ensure exports/types compile, and run unit/build
checks to confirm no breaking changes.
---
Nitpick comments:
In @.beads/ss-dx5.5.json:
- Line 7: Update the "status" value in the JSON from "open" to "closed" (or an
appropriate completed state) and edit the "notes" checklist so items implemented
in this PR are checked ([x]) while leaving deferred items unchecked;
specifically mark chain-adapters, caip, feature-flag, plugin, env-config,
fee-asset-config and the two RELAY ACTIVATION lines (Add to
chainIdToRelayChainId and Add native asset case) as completed [x], and leave
asset-service and icon/logo unchecked. Ensure the "notes" string preserves
formatting and only the checklist markers are changed.
In @.env.development:
- Line 67: Lint flags indicate two .env keys are out of alphabetical order:
VITE_BERACHAIN_NODE_URL and VITE_FEATURE_BERACHAIN; to fix, move
VITE_BERACHAIN_NODE_URL so it appears alphabetically before
VITE_BNBSMARTCHAIN_NODE_URL and move VITE_FEATURE_BERACHAIN so it appears
alphabetically before VITE_FEATURE_CETUS_SWAP (or reorder the surrounding
section alphabetically), ensuring the variable names and their values remain
unchanged.
In `@src/plugins/berachain/index.tsx`:
- Around line 25-35: The code calls fromAssetId(asset.assetId) twice — once in
the filter and again in the map — causing redundant parsing; change the pipeline
to parse once per asset (e.g., replace the filter+map with a single pass that
extracts parsed = fromAssetId(asset.assetId) and uses
parsed.chainId/parsed.assetNamespace to filter and parsed.assetReference for
contractAddress) so functions like fromAssetId, filter, and map operate on the
parsed result for each asset rather than re-parsing.
In `@src/vite-env.d.ts`:
- Around line 119-120: The VITE_FEATURE_BERACHAIN declaration is grouped under
"URLs and API keys" but should be with other feature flags for consistency; move
the line declaring readonly VITE_FEATURE_BERACHAIN into the "Feature flags –
present in all envs" block alongside VITE_FEATURE_INK and VITE_INK_NODE_URL,
updating the surrounding comment blocks so feature flags are grouped together
while leaving the interface flat and unchanged otherwise.
Description
Integrate Berachain (eip155:80094) as a second-class EVM citizen via the Relay bridge swapper.
Changes include:
berachainChainId,berachainAssetId) andKnownChainIds.BerachainMainnetBerachainChainAdapterextendingSecondClassEvmAdapterwith BERA as native tokenviemBerachainClient) and ethers provider singletonsberachain-beraplatform)eth_getTransactionReceiptinuseSendActionSubscriberBerachainfeature flagNot yet included (requires Zerion API key):
yarn generate:asset-data)Issue (if applicable)
closes #11902 (partial — Berachain only)
Risk
Low risk — behind
VITE_FEATURE_BERACHAINfeature flag (default: false). No impact to existing chains.Testing
Engineering
VITE_FEATURE_BERACHAIN=truein.env.developmentyarn build:packages && yarn devOperations
Summary by CodeRabbit
New Features
Chores