Skip to content

feat: integrate Sei (eip155:1329) as second-class citizen via Relay#11928

Closed
NeOMakinG wants to merge 2 commits intodevelopfrom
feat/integrate-sei-relay
Closed

feat: integrate Sei (eip155:1329) as second-class citizen via Relay#11928
NeOMakinG wants to merge 2 commits intodevelopfrom
feat/integrate-sei-relay

Conversation

@NeOMakinG
Copy link
Collaborator

@NeOMakinG NeOMakinG commented Feb 17, 2026

Description

Integrate Sei EVM chain (eip155:1329) as a second-class citizen in ShapeShift Web via Relay.link bridge support.

Changes include:

  • CAIP identifiers (seiChainId, seiAssetId, CHAIN_REFERENCE.SeiMainnet)
  • HDWallet support flags across all wallet implementations (native, ledger, trezor, metamask-multichain, wc2 = true; coinbase, gridplus, keepkey, phantom, vultisig = false)
  • Chain adapter (SeiChainAdapter extending EvmBaseAdapter)
  • Viem client and ethers provider configuration
  • Feature flag (VITE_FEATURE_SEI) with dev-only enablement
  • Plugin registration and wallet support hooks
  • CoinGecko adapter with sei-v2 platform mapping
  • Zerion chain mapping
  • Relay swapper chain mapping (no Across support)
  • CSP headers for RPC endpoint
  • Asset generation scripts
  • Market/portfolio/opportunities integration
  • Popular assets discoverability
  • CoinGecko supported chain IDs (feature-flagged)

⚠️ Relay does support only any chain to USDC.N on SEI, we will need to find another swapper, opening this PR in the meantime

Issue (if applicable)

Part of #11902

Risk

Low risk — all changes are behind the VITE_FEATURE_SEI feature flag (disabled in production). No existing chains or transaction flows are affected.

No protocols, transaction types, wallets or contract interactions are affected — this is a new chain addition behind a feature flag.

Testing

Engineering

  1. Enable the Sei feature flag in .env.development (VITE_FEATURE_SEI=true)
  2. Verify Sei appears as an available chain in the app
  3. Verify the Sei native asset (SEI) appears in asset lists
  4. Verify wallet support detection works correctly for supported wallet types
  5. Run yarn lint and yarn type-check — both should pass

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

Screenshots (if applicable)

image
  • Derivation is fine
  • Swapping from any chain to USDC.N seems to be working
  • Balance is updated after the swap
  • Popular assets/assets are showing as expected
  • Market data is showing as expected

N/A — chain integration behind feature flag

Summary by CodeRabbit

Release Notes

  • New Features
    • Integrated Sei blockchain network with comprehensive wallet support
    • Enabled Sei token trading, portfolio tracking, and asset discovery
    • Added transaction monitoring and fee estimation for Sei
    • Sei support can be toggled through feature settings

Add Sei EVM chain support including:
- CAIP identifiers (seiChainId, seiAssetId)
- HDWallet support flags across all wallet implementations
- Chain adapter (SeiChainAdapter extending EvmBaseAdapter)
- Viem client and ethers provider configuration
- Feature flag (VITE_FEATURE_SEI) with dev-only enablement
- Plugin registration and wallet support hooks
- CoinGecko adapter with sei-v2 platform mapping
- Zerion chain mapping
- Relay swapper chain mapping
- CSP headers for RPC endpoint
- Asset generation scripts
- Market/portfolio/opportunities integration
- Popular assets discoverability

Part of #11902
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 17, 2026

📝 Walkthrough

Walkthrough

This PR introduces comprehensive Sei mainnet support across the application by adding environment variables, CSP headers, CAIP constants, chain adapters, HDWallet capability flags, Coingecko mappings, asset definitions, and plugin registration with feature flag gating to control availability.

Changes

Cohort / File(s) Summary
Environment & Configuration
.env, .env.development, src/config.ts
Added Sei RPC node URL and feature flag environment variables with validation; enabled by default in development.
Security & Headers
headers/csps/chains/sei.ts, headers/csps/index.ts
Created Sei CSP configuration module and registered it in the CSP export array with connect-src directive.
Type Definitions & Enums
packages/types/src/base.ts, packages/types/src/zerion.ts
Added KnownChainIds.SeiMainnet enum value, updated EvmChainId union type, and extended Zerion chain mappings.
CAIP Constants & Mappings
packages/caip/src/constants.ts, packages/caip/src/adapters/coingecko/index.ts, packages/caip/src/adapters/coingecko/utils.ts, packages/caip/src/adapters/coingecko/utils.test.ts
Defined seiAssetId/seiChainId constants, added Sei to Coingecko asset platform enum, wired Coingecko mappings, and updated test expectations.
Chain Adapters & EVM Support
packages/chain-adapters/src/evm/EvmBaseAdapter.ts, packages/chain-adapters/src/evm/index.ts, packages/chain-adapters/src/evm/sei/SeiChainAdapter.ts, packages/chain-adapters/src/evm/sei/index.ts, packages/chain-adapters/src/types.ts
Implemented Sei-specific chain adapter extending SecondClassEvmAdapter, added BIP44 parameters, wired into EVM chain mappings and type system (Account, FeeData, SignTx, BuildTxData, GetFeeDataInput).
EVM Clients & Contracts
packages/contracts/src/ethersProviderSingleton.ts, packages/contracts/src/viemClient.ts
Added Sei node URL routing in ethers singleton and created viem Sei client with chain-to-client mappings.
HDWallet Support Flags
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
Added readonly _supportsSei flag across all HDWallet implementations; set true for Ledger, MetaMaskMultiChain, Native, Trezor, and WalletConnectV2; set false for others. Added supportsSei type guard in core wallet module.
Swapper Integration
packages/swapper/src/swappers/RelaySwapper/constant.ts, packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts
Added Sei to relay chain ID mappings and asset reference resolution for native assets.
Asset Utilities
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
Defined seiChain asset with metadata (name, symbol, icon, explorer), wired Sei into asset lookups, fee asset resolution, and chain short name mapping.
Asset Data Generation
scripts/generateAssetData/coingecko.ts, scripts/generateAssetData/generateAssetData.ts, scripts/generateAssetData/sei/index.ts
Created Sei asset generation module, integrated into coingecko provider with explorer metadata, and added to asset aggregation pipeline.
Feature Flags & State
src/config.ts, src/constants/chains.ts, src/state/slices/preferencesSlice/preferencesSlice.ts, src/test/mocks/store.ts
Added Sei feature flag to Redux state and mock store; added SeiMainnet to SECOND_CLASS_CHAINS with conditional filtering based on feature flag.
Plugin System & Context
src/plugins/activePlugins.ts, src/plugins/sei/index.tsx, src/context/PluginProvider/PluginProvider.tsx
Registered Sei plugin in active plugins array; implemented Sei chain adapter registration with dynamic token list from asset service; added feature flag gating in plugin provider.
UI Components & Hooks
src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx, src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts, src/pages/Markets/components/MarketsRow.tsx, src/lib/account/evm.ts, src/lib/asset-service/service/AssetService.ts, src/lib/coingecko/utils.ts, src/state/slices/portfolioSlice/utils/index.ts
Integrated Sei with feature flag checks across trade asset search, wallet chain support, markets display, account processing, asset filtering, and portfolio utilities.
Sei Utilities
src/lib/utils/sei.ts
Added isSeiChainAdapter type guard, assertGetSeiChainAdapter validation helper, and getSeiTransactionStatus async function for JSON-RPC transaction receipt polling with TxStatus mapping.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

enhancement, blockchain-integration, feature-gate

Suggested reviewers

  • 0xApotheosis
  • gomesalexandre
  • premiumjibles

Poem

🐰 A new chain arrives with SEI so bright,
Feature flags dancing left and right,
Adapters wired, wallets aligned,
Assets mapped with care refined.
From RPC nodes to token lists neat,
Sei's integration is oh-so-sweet! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: integrating Sei (eip155:1329) as a second-class citizen via Relay, which is the primary objective evident from the extensive changes across the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/integrate-sei-relay

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@NeOMakinG NeOMakinG marked this pull request as ready for review February 18, 2026 09:17
@NeOMakinG NeOMakinG requested a review from a team as a code owner February 18, 2026 09:17
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
packages/utils/src/assetData/baseAssets.ts (1)

392-407: Nit: seiChain naming is inconsistent with peer exports.

Every other export in this file uses a plain lowercase chain name (katana, monad, hyperevm, plasma, megaeth, solana, etc.). Renaming to sei would align with the pattern, but there's no functional impact.

♻️ Proposed rename
-export const seiChain: Readonly<Asset> = Object.freeze({
+export const sei: Readonly<Asset> = Object.freeze({

And the corresponding update in getBaseAsset.ts:

-import { ..., seiChain, ... } from './baseAssets'
+import { ..., sei, ... } from './baseAssets'
 ...
-  case KnownChainIds.SeiMainnet: return seiChain
+  case KnownChainIds.SeiMainnet: return sei
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/utils/src/assetData/baseAssets.ts` around lines 392 - 407, Rename
the exported constant seiChain to match the file's lowercase chain-name pattern
(rename export const seiChain: Readonly<Asset> to export const sei:
Readonly<Asset>) and update all internal references/imports accordingly (e.g.,
any usage in getBaseAsset.ts and any maps or lookups that reference seiChain).
Ensure the exported identifier is updated everywhere in the repo so type
annotations and imports still resolve to the same Readonly<Asset> value and run
type checks to catch missed references.
.env.development (1)

99-99: Optional: key ordering nit flagged by dotenv-linter.

VITE_FEATURE_SEI should precede VITE_FEATURE_WC_DIRECT_CONNECTION alphabetically. No functional impact.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env.development at line 99, Reorder the environment keys so
VITE_FEATURE_SEI appears alphabetically before VITE_FEATURE_WC_DIRECT_CONNECTION
in the .env.development file; specifically, move the VITE_FEATURE_SEI line so it
is placed above the VITE_FEATURE_WC_DIRECT_CONNECTION entry to satisfy
dotenv-linter's alphabetical key ordering check.
.env (1)

308-308: Optional: key ordering nit flagged by dotenv-linter.

VITE_FEATURE_SEI should precede VITE_FEATURE_SUNIO_SWAP alphabetically. No functional impact.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env at line 308, Reorder the environment keys so they are alphabetically
sorted: move the VITE_FEATURE_SEI entry to come before VITE_FEATURE_SUNIO_SWAP;
update the .env ordering only (no value changes) to satisfy dotenv-linter's
alphabetical check.
src/plugins/sei/index.tsx (1)

22-36: fromAssetId is called twice per asset — once in the filter and again in the map. A single reduce pass (or flatMap with a combined predicate) would be more efficient.

♻️ Suggested refactor
-              const getKnownTokens = () => {
-                const assetService = getAssetService()
-                return assetService.assets
-                  .filter(asset => {
-                    const { chainId, assetNamespace } = fromAssetId(asset.assetId)
-                    return chainId === seiChainId && assetNamespace === 'erc20'
-                  })
-                  .map(asset => ({
-                    assetId: asset.assetId,
-                    contractAddress: fromAssetId(asset.assetId).assetReference,
-                    symbol: asset.symbol,
-                    name: asset.name,
-                    precision: asset.precision,
-                  }))
-              }
+              const getKnownTokens = () => {
+                const assetService = getAssetService()
+                return assetService.assets.reduce<ReturnType<typeof sei.ChainAdapter.prototype.getKnownTokens extends () => infer R ? () => R : never>>((acc, asset) => {
+                  // simpler: inline reduce
+                }, [])
+              }

Or more simply:

 const getKnownTokens = () => {
   const assetService = getAssetService()
-  return assetService.assets
-    .filter(asset => {
-      const { chainId, assetNamespace } = fromAssetId(asset.assetId)
-      return chainId === seiChainId && 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<{ assetId: string; contractAddress: string; symbol: string; name: string; precision: number }[]>((acc, asset) => {
+    const { chainId, assetNamespace, assetReference } = fromAssetId(asset.assetId)
+    if (chainId === seiChainId && 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/sei/index.tsx` around lines 22 - 36, getKnownTokens currently
calls fromAssetId twice per asset (once in the filter and again in the map),
wasting CPU; update getKnownTokens to perform a single pass and call fromAssetId
only once per asset—either replace the filter+map pair with a single reduce over
assetService.assets or use map that first computes const info =
fromAssetId(asset.assetId) and returns the token only when info.chainId ===
seiChainId && info.assetNamespace === 'erc20'; keep the same returned shape
(assetId, contractAddress from info.assetReference, symbol, name, precision) and
retain the use of getAssetService()/assetService.assets and the seiChainId
constant.
src/lib/utils/sei.ts (1)

10-17: isSeiChainAdapter duplicates the one already exported from SeiChainAdapter.ts — the two differ in the checked method (getChainId() here vs getType() there), null-handling, and return type. Consider importing and wrapping the package-level guard instead of re-implementing it.

♻️ Suggested refactor
+import { isSeiChainAdapter as _isSeiChainAdapter } from '@shapeshiftoss/chain-adapters'
 
 export const isSeiChainAdapter = (chainAdapter: unknown): chainAdapter is EvmChainAdapter => {
   if (!chainAdapter) return false
-
-  const maybeAdapter = chainAdapter as EvmChainAdapter
-  if (typeof maybeAdapter.getChainId !== 'function') return false
-
-  return maybeAdapter.getChainId() === seiChainId
+  return _isSeiChainAdapter(chainAdapter)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/utils/sei.ts` around lines 10 - 17, Replace this duplicate type-guard
with a thin wrapper around the package-level guard exported from
SeiChainAdapter.ts: import the existing isSeiChainAdapter from
SeiChainAdapter.ts and have this module re-export or call that function instead
of re-implementing it; ensure your wrapper handles falsy inputs identically
(return false for null/undefined), and keep the same type predicate signature
exported here (chainAdapter is EvmChainAdapter) so callers' types still narrow
correctly while relying on the canonical implementation (which uses getType())
rather than the duplicated getChainId() check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/chain-adapters/src/evm/sei/SeiChainAdapter.ts`:
- Around line 18-20: The type-guard isSeiChainAdapter currently calls (adapter
as ChainAdapter).getType() without null/undefined protection and will throw for
nullish inputs; update isSeiChainAdapter to first check adapter is not
null/undefined and that (adapter as any).getType is a function before calling
it, then return whether getType() === KnownChainIds.SeiMainnet (referencing
isSeiChainAdapter, getType, and KnownChainIds.SeiMainnet in your change).

---

Nitpick comments:
In @.env:
- Line 308: Reorder the environment keys so they are alphabetically sorted: move
the VITE_FEATURE_SEI entry to come before VITE_FEATURE_SUNIO_SWAP; update the
.env ordering only (no value changes) to satisfy dotenv-linter's alphabetical
check.

In @.env.development:
- Line 99: Reorder the environment keys so VITE_FEATURE_SEI appears
alphabetically before VITE_FEATURE_WC_DIRECT_CONNECTION in the .env.development
file; specifically, move the VITE_FEATURE_SEI line so it is placed above the
VITE_FEATURE_WC_DIRECT_CONNECTION entry to satisfy dotenv-linter's alphabetical
key ordering check.

In `@packages/utils/src/assetData/baseAssets.ts`:
- Around line 392-407: Rename the exported constant seiChain to match the file's
lowercase chain-name pattern (rename export const seiChain: Readonly<Asset> to
export const sei: Readonly<Asset>) and update all internal references/imports
accordingly (e.g., any usage in getBaseAsset.ts and any maps or lookups that
reference seiChain). Ensure the exported identifier is updated everywhere in the
repo so type annotations and imports still resolve to the same Readonly<Asset>
value and run type checks to catch missed references.

In `@src/lib/utils/sei.ts`:
- Around line 10-17: Replace this duplicate type-guard with a thin wrapper
around the package-level guard exported from SeiChainAdapter.ts: import the
existing isSeiChainAdapter from SeiChainAdapter.ts and have this module
re-export or call that function instead of re-implementing it; ensure your
wrapper handles falsy inputs identically (return false for null/undefined), and
keep the same type predicate signature exported here (chainAdapter is
EvmChainAdapter) so callers' types still narrow correctly while relying on the
canonical implementation (which uses getType()) rather than the duplicated
getChainId() check.

In `@src/plugins/sei/index.tsx`:
- Around line 22-36: getKnownTokens currently calls fromAssetId twice per asset
(once in the filter and again in the map), wasting CPU; update getKnownTokens to
perform a single pass and call fromAssetId only once per asset—either replace
the filter+map pair with a single reduce over assetService.assets or use map
that first computes const info = fromAssetId(asset.assetId) and returns the
token only when info.chainId === seiChainId && info.assetNamespace === 'erc20';
keep the same returned shape (assetId, contractAddress from info.assetReference,
symbol, name, precision) and retain the use of
getAssetService()/assetService.assets and the seiChainId constant.

Comment on lines +18 to +20
export const isSeiChainAdapter = (adapter: unknown): adapter is ChainAdapter => {
return (adapter as ChainAdapter).getType() === KnownChainIds.SeiMainnet
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

isSeiChainAdapter will throw on null/undefined input — the adapter: unknown type does not preclude null, and (adapter as ChainAdapter).getType() will produce a TypeError without a null guard.

🛡️ Proposed fix
 export const isSeiChainAdapter = (adapter: unknown): adapter is ChainAdapter => {
+  if (!adapter) return false
   return (adapter as ChainAdapter).getType() === KnownChainIds.SeiMainnet
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/chain-adapters/src/evm/sei/SeiChainAdapter.ts` around lines 18 - 20,
The type-guard isSeiChainAdapter currently calls (adapter as
ChainAdapter).getType() without null/undefined protection and will throw for
nullish inputs; update isSeiChainAdapter to first check adapter is not
null/undefined and that (adapter as any).getType is a function before calling
it, then return whether getType() === KnownChainIds.SeiMainnet (referencing
isSeiChainAdapter, getType, and KnownChainIds.SeiMainnet in your change).

@NeOMakinG NeOMakinG marked this pull request as draft February 18, 2026 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant