Skip to content

feat: integrate Tempo chain as second-class EVM citizen#12194

Draft
gomesalexandre wants to merge 5 commits intoshapeshift:developfrom
gomesalexandre:feat/tempo-chain
Draft

feat: integrate Tempo chain as second-class EVM citizen#12194
gomesalexandre wants to merge 5 commits intoshapeshift:developfrom
gomesalexandre:feat/tempo-chain

Conversation

@gomesalexandre
Copy link
Contributor

@gomesalexandre gomesalexandre commented Mar 19, 2026

Description

Pretty much what it says on the box, but not quite a normal second-class evm chain PR.

Tempo is weirdy boi:

  • there is chain metadata for native USD
  • practical swappable / fee-paying assets are Tempo tokens like USDC and pathUSD
  • same-chain execution needed Tempo-specific fee-token handling and typed tx plumbing instead of us blindly pretending this is just another vanilla evm gas coin setup

So this PR now does a bunch more than the original crate predicates:

  • add Tempo USDC + pathUSD asset generation / related asset data / manifest outputs
  • make Tempo trade asset discoverability less sad
  • plumb Tempo fee-token semantics through swapper quote + execution paths
  • make send flow handle Tempo token-denominated fees sanely
  • wire Tempo execution payload support through wallet providers
  • add a qabot regression fixture for:
    • Tempo chain discoverability
    • Tempo asset picker/icon sanity
    • cross-chain ETH -> Tempo USDC
    • same-chain USDC -> pathUSD
    • same-chain pathUSD -> USDC
    • Tempo token self-send coverage

This is still pretty hacky and absolutely not code-reviewed enough yet. Functionally though, she worky now.

qabot evidence:

Issue (if applicable)

closes #

Risk

Medium-ish.

Behind VITE_FEATURE_TEMPO, yes, but this stopped being a tiny isolated chain PR the moment Tempo's fee semantics turned out not to be normal native-gas evm semantics.

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

  • Tempo send flow
  • Tempo same-chain + cross-chain Relay swap execution
  • wallet provider eth_sendTransaction payload handling for Tempo txs
  • native wallet signing for Tempo txs

Testing

Engineering

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)
  • if enabling locally, set VITE_FEATURE_TEMPO=true
  • verify Tempo shows in trade chain selection
  • verify Tempo USDC and pathUSD are selectable and icons look sane
  • verify cross-chain into Tempo USDC
  • verify same-chain USDC <-> pathUSD

Screenshots (if applicable)

qabot run above has the actual evidence trail

@gomesalexandre gomesalexandre requested a review from a team as a code owner March 19, 2026 01:40
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds Tempo (chain ID 4217) as a feature‑gated second‑class EVM chain across environment/config, CSP, CAIP constants, viem/ethers clients, a Tempo chain adapter, wallet capability flags, asset generation, swapper mappings, plugin registration, and UI/state gating.

Changes

Cohort / File(s) Summary
Environment & Types
\.env, \.env.development, src/vite-env.d.ts, src/config.ts
Added VITE_TEMPO_NODE_URL and VITE_FEATURE_TEMPO, dev default RPC, validators, and added env types.
CSP
headers/csps/chains/tempo.ts, headers/csps/index.ts
New Tempo CSP entry using configured RPC + fallback; added to CSP index.
CAIP & Chain Constants
packages/types/src/base.ts, packages/caip/src/constants.ts, chains/tempo.json, src/constants/chains.ts
Introduced KnownChainIds.TempoMainnet, tempoChainId/tempoAssetId, tempo chain metadata JSON, and included Tempo in second‑class chains.
Viem / Ethers Clients & RPCs
packages/contracts/src/viemClient.ts, packages/contracts/src/fallbackRpcUrls.ts, packages/contracts/src/ethersProviderSingleton.ts
Defined tempoChain, viemTempoClient, added fallback RPC URL and ethers provider RPC resolution for Tempo.
Chain Adapter
packages/chain-adapters/src/evm/tempo/TempoChainAdapter.ts, packages/chain-adapters/src/evm/tempo/index.ts, packages/chain-adapters/src/evm/index.ts, packages/chain-adapters/src/evm/EvmBaseAdapter.ts, packages/chain-adapters/src/types.ts
Added Tempo ChainAdapter class, exports, included Tempo in evmChainIds, added type mappings and wallet support assertion branch.
HDWallet Capability Flags & Guard
packages/hdwallet-core/src/ethereum.ts, packages/hdwallet-core/src/wallet.ts, packages/hdwallet-*/src/*.ts (multiple)
Added _supportsTempo to ETHWalletInfo, supportsTempo() guard, and set _supportsTempo true/false across wallet implementations.
Swapper & Token Mapping
packages/swapper/src/swappers/RelaySwapper/constant.ts, .../relayTokenToAssetId.ts
Added tempo chain id mapping for Relay and native asset mapping for Tempo (slip44:60).
Asset Data & Utilities
packages/utils/src/assetData/baseAssets.ts, getBaseAsset.ts, chainIdToFeeAssetId.ts, getAssetNamespaceFromChainId.ts, getChainShortName.ts, getNativeFeeAssetReference.ts
Added tempo base asset, added Tempo branches for asset/fee/namespace/short name resolution.
Asset Generation Scripts
scripts/generateAssetData/tempo/index.ts, scripts/generateAssetData/generateAssetData.ts, scripts/generateAssetData/coingecko.ts, scripts/addChain/*
New tempo asset fetcher and pipeline inclusion; codegen/schema changes to allow nullable relatedAssetKey.
Plugin & App Integration
src/plugins/tempo/index.tsx, src/plugins/activePlugins.ts, src/context/PluginProvider/PluginProvider.tsx, src/context/WalletProvider/WalletConnectV2/config.ts
Added Tempo plugin registering a lazy ChainAdapter (uses config RPC + assetService tokens), registered plugin, added WalletConnect v2 RPC mapping and feature gating in plugin provider.
Feature Flags, State & UI Gating
src/state/slices/preferencesSlice/preferencesSlice.ts, src/test/mocks/store.ts, src/state/migrations/index.ts, src/state/slices/opportunitiesSlice/mappings.ts, src/pages/Markets/components/MarketsRow.tsx, src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx
Added Tempo feature flag, mock default, migration bump, empty DeFi mapping, and UI/state filters to exclude/include Tempo based on flag.
Wallet Support Logic & Accounts
src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts, src/lib/account/evm.ts, src/state/slices/portfolioSlice/utils/index.ts
Added support checks using supportsTempo and feature flag gating to wallet/derive/account logic.
Coingecko Adapter & Tests
packages/caip/src/adapters/coingecko/index.ts, packages/caip/src/adapters/coingecko/utils.ts, .../utils.test.ts
Added CoingeckoAssetPlatform.Tempo mapping to tempoChainId, parsing logic to include Tempo platform tokens, and updated test expectations.
Asset Service & Coingecko utils
src/lib/asset-service/service/AssetService.ts, src/lib/coingecko/utils.ts
Asset selection and Coingecko-supported chain list now conditionally include/exclude Tempo via feature flag.

Sequence Diagram(s)

sequenceDiagram
  participant App as App (Plugin loader)
  participant Plugin as Tempo Plugin
  participant Adapter as Tempo ChainAdapter
  participant Viem as viemTempoClient
  participant AssetSvc as AssetService

  App->>Plugin: register() (feature-flagged)
  Plugin->>Adapter: create ChainAdapter(rpcUrl, getKnownTokens)
  Adapter->>Viem: use viemTempoClient (RPC/fallbacks)
  Plugin->>AssetSvc: getKnownTokens() -> assets
  AssetSvc-->>Plugin: filtered tempo ERC20 tokens
  Plugin-->>App: plugin with tempo ChainAdapter
  App->>Adapter: wallet action -> adapter asserts supportsTempo(wallet)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • NeOMakinG

"I hopped through code, nose twitching with glee,
A Tempo sprout added — chain ID four-two-one-seven, whee!
Flags set to gate, adapters primed to race,
Tokens fetched and routed to their place,
The warren hums in sync — a new chain to see!" 🐇✨

🚥 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
Title check ✅ Passed The title clearly and specifically describes the main change: integrating Tempo as a second-class EVM chain. It is concise, directly related to the changeset, and communicates the primary objective.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/state/slices/portfolioSlice/utils/index.ts (1)

136-179: ⚠️ Potential issue | 🟡 Minor

Missing tempoChainId in accountIdToLabel switch statement.

The accountIdToLabel function handles most EVM chains (including other second-class chains like soneiumChainId, celoChainId, monadChainId, plasmaChainId) to return middleEllipsis(pubkey), but tempoChainId is not included. This will cause Tempo accounts to fall through to the default case returning an empty string.

Proposed fix
     case soneiumChainId:
+    case tempoChainId:
     case thorchainChainId:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/state/slices/portfolioSlice/utils/index.ts` around lines 136 - 179, The
switch in accountIdToLabel is missing tempoChainId so Tempo accounts fall
through to the default; add a case for tempoChainId alongside the other chainId
cases (the same block that returns middleEllipsis(pubkey)) so tempoChainId
triggers return middleEllipsis(pubkey); locate accountIdToLabel and add the
tempoChainId case near the other EVM/second-class chainId cases.
🧹 Nitpick comments (2)
headers/csps/chains/tempo.ts (1)

1-9: Pattern inconsistency with other CSP chain files.

Based on learnings, CSP files in headers/csps/chains/ typically use Vite's loadEnv() pattern directly (like plasma.ts, monad.ts) rather than getConfig() from src/config.ts. While this implementation is functionally correct, it deviates from the established convention for consistency.

♻️ Suggested refactor to match other CSP chain files
 import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls'
+import { loadEnv } from 'vite'

-import { getConfig } from '@/config'
-
-const env = getConfig()
+const env = loadEnv(process.env.NODE_ENV ?? 'development', process.cwd(), '')

 export const csp = {
   'connect-src': [env.VITE_TEMPO_NODE_URL, ...FALLBACK_RPC_URLS.tempo],
 } as const

Based on learnings: "For CSP files in headers/csps/chains/, gomesalexandre prefers using Vite's loadEnv() pattern directly to load environment variables... for consistency with existing second-class chain CSP files."

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

In `@headers/csps/chains/tempo.ts` around lines 1 - 9, The CSP module csp
currently imports getConfig() and uses env.VITE_TEMPO_NODE_URL (getConfig) which
is inconsistent with other chain CSP files; replace getConfig() usage by loading
Vite env directly with loadEnv() and use the VITE_TEMPO_NODE_URL value from that
env (keep FALLBACK_RPC_URLS.tempo and the exported csp object intact) so the
file follows the same loadEnv pattern as plasma.ts/monad.ts; update imports
accordingly and ensure the exported csp still uses the resulting
VITE_TEMPO_NODE_URL and FALLBACK_RPC_URLS.tempo.
src/plugins/tempo/index.tsx (1)

25-35: Parse each asset ID once in getKnownTokens.

fromAssetId(asset.assetId) is called twice per matching asset. You can parse once and reuse the parsed fields for clarity and less repeated work.

♻️ Optional refactor
                 return assetService.assets
-                  .filter(asset => {
-                    const { chainId, assetNamespace } = fromAssetId(asset.assetId)
-                    return chainId === tempoChainId && assetNamespace === 'erc20'
-                  })
-                  .map(asset => ({
-                    assetId: asset.assetId,
-                    contractAddress: fromAssetId(asset.assetId).assetReference,
-                    symbol: asset.symbol,
-                    name: asset.name,
-                    precision: asset.precision,
-                  }))
+                  .map(asset => ({ asset, parsed: fromAssetId(asset.assetId) }))
+                  .filter(
+                    ({ parsed }) => parsed.chainId === tempoChainId && parsed.assetNamespace === 'erc20',
+                  )
+                  .map(({ asset, parsed }) => ({
+                    assetId: asset.assetId,
+                    contractAddress: parsed.assetReference,
+                    symbol: asset.symbol,
+                    name: asset.name,
+                    precision: asset.precision,
+                  }))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/tempo/index.tsx` around lines 25 - 35, In getKnownTokens, avoid
parsing the same assetId twice: inside the .filter/.map chain call
fromAssetId(asset.assetId) once per asset, e.g., store the result (const {
chainId, assetNamespace, assetReference } = fromAssetId(asset.assetId)) and use
those variables for both the filter check (chainId === tempoChainId &&
assetNamespace === 'erc20') and when building the mapped object (use
assetReference for contractAddress); update the .filter/.map so each assetId is
parsed only once and reused.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/vite-env.d.ts`:
- Around line 67-68: The interface ImportMetaEnv contains a duplicated member
VITE_TEMPO_NODE_URL; remove the redundant VITE_TEMPO_NODE_URL declaration so the
ImportMetaEnv interface only declares that env var once (matching other chain
node URL entries), then run TypeScript checks to verify no remaining duplicate
declarations or regressions.

---

Outside diff comments:
In `@src/state/slices/portfolioSlice/utils/index.ts`:
- Around line 136-179: The switch in accountIdToLabel is missing tempoChainId so
Tempo accounts fall through to the default; add a case for tempoChainId
alongside the other chainId cases (the same block that returns
middleEllipsis(pubkey)) so tempoChainId triggers return middleEllipsis(pubkey);
locate accountIdToLabel and add the tempoChainId case near the other
EVM/second-class chainId cases.

---

Nitpick comments:
In `@headers/csps/chains/tempo.ts`:
- Around line 1-9: The CSP module csp currently imports getConfig() and uses
env.VITE_TEMPO_NODE_URL (getConfig) which is inconsistent with other chain CSP
files; replace getConfig() usage by loading Vite env directly with loadEnv() and
use the VITE_TEMPO_NODE_URL value from that env (keep FALLBACK_RPC_URLS.tempo
and the exported csp object intact) so the file follows the same loadEnv pattern
as plasma.ts/monad.ts; update imports accordingly and ensure the exported csp
still uses the resulting VITE_TEMPO_NODE_URL and FALLBACK_RPC_URLS.tempo.

In `@src/plugins/tempo/index.tsx`:
- Around line 25-35: In getKnownTokens, avoid parsing the same assetId twice:
inside the .filter/.map chain call fromAssetId(asset.assetId) once per asset,
e.g., store the result (const { chainId, assetNamespace, assetReference } =
fromAssetId(asset.assetId)) and use those variables for both the filter check
(chainId === tempoChainId && assetNamespace === 'erc20') and when building the
mapped object (use assetReference for contractAddress); update the .filter/.map
so each assetId is parsed only once and reused.
🪄 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: 8433a0ba-145a-433a-9676-17ad26773af3

📥 Commits

Reviewing files that changed from the base of the PR and between a209894 and 5ed4bd9.

⛔ Files ignored due to path filters (48)
  • packages/caip/src/adapters/coincap/generated/eip155_1/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_10/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_137/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_42161/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_43114/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_56/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_8453/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/solana_5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_1/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_10/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_100/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_130/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_137/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_143/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_146/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_25/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_324/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_34443/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_42161/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_4217/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_42220/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_43114/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_480/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_5000/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_534352/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_56/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_59144/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_747/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_747474/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_80094/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_81457/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_8453/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_98866/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_999/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/index.ts is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/near_mainnet/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/solana_5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/starknet_SN_MAIN/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/sui_35834a8a/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/ton_mainnet/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/tron_0x2b6653dc/adapter.json is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • public/generated/asset-manifest.json is excluded by !**/generated/**
  • public/generated/asset-manifest.json.br is excluded by !**/generated/**
  • public/generated/asset-manifest.json.gz is excluded by !**/*.gz, !**/generated/**
  • public/generated/generatedAssetData.json is excluded by !**/generated/**
  • public/generated/generatedAssetData.json.br is excluded by !**/generated/**
  • public/generated/generatedAssetData.json.gz is excluded by !**/*.gz, !**/generated/**
📒 Files selected for processing (69)
  • .env
  • .env.development
  • headers/csps/chains/tempo.ts
  • headers/csps/index.ts
  • package.json
  • 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/package.json
  • packages/chain-adapters/src/evm/EvmBaseAdapter.ts
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/tempo/TempoChainAdapter.ts
  • packages/chain-adapters/src/evm/tempo/index.ts
  • packages/chain-adapters/src/types.ts
  • packages/contracts/package.json
  • packages/contracts/src/ethersProviderSingleton.ts
  • packages/contracts/src/fallbackRpcUrls.ts
  • packages/contracts/src/viemClient.ts
  • packages/hdwallet-coinbase/src/coinbase.ts
  • packages/hdwallet-core/src/ethereum.ts
  • packages/hdwallet-core/src/utils.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/native-multichain.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/package.json
  • packages/swapper/src/swappers/RelaySwapper/constant.ts
  • packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts
  • packages/types/package.json
  • packages/types/src/base.ts
  • packages/types/src/zerion.ts
  • packages/unchained-client/package.json
  • 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
  • scripts/generateAssetData/tempo/index.ts
  • src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx
  • src/config.ts
  • src/constants/chains.ts
  • src/context/PluginProvider/PluginProvider.tsx
  • src/context/WalletProvider/WalletConnectV2/config.ts
  • src/hooks/useWalletSupportsChain/checkWalletHasRuntimeSupport.test.ts
  • 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/plugins/activePlugins.ts
  • src/plugins/tempo/index.tsx
  • src/state/migrations/index.ts
  • 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

@gomesalexandre gomesalexandre changed the title feat: integrate Tempo chain feat: integrate Tempo chain as second-class EVM citizen Mar 19, 2026
Copy link
Collaborator

@NeOMakinG NeOMakinG left a comment

Choose a reason for hiding this comment

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

CI passing ✅

Code review notes:

  • Chain integration follows standard second-class EVM pattern
  • Feature flag (VITE_FEATURE_TEMPO) properly configured
  • HDWallet support flags added correctly
  • CAIP constants and chain adapters look correct

Note: Unable to complete full browser testing due to dev server dependency issues when switching branches, but CI validates the implementation. Recommend manual QA verification before merge.

@gomesalexandre
Copy link
Contributor Author

qabot — Tempo Chain Integration ✅

5/5 steps passed | Dashboard

Step Status
App loads
Wallet import and unlock
Trade page swap interface
Tempo chain in selector
No regressions

Tested with VITE_FEATURE_TEMPO=true on local dev server. Tempo appears in chain selector, existing swap UI works correctly.

- Chain ID 4217, native currency USD (stablecoin-native L1)
- RPC: https://rpc.tempo.xyz, Explorer: https://explore.tempo.xyz
- HDWallet support flags across all wallet implementations
- SecondClassEvmAdapter chain adapter
- Relay swapper integration (relayChainId 4217)
- CoinGecko platform adapter (tempo)
- Plugin with feature flag VITE_FEATURE_TEMPO
- CSP headers, viem client (defineChain), ethers provider
- State migration clearAssets
- Generated assets via generate:chain
- Fix addChain scaffolder: allow null relatedAssetKey, fix codemod template

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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: 2

🧹 Nitpick comments (1)
packages/chain-adapters/src/evm/tempo/TempoChainAdapter.ts (1)

40-45: Add explicit return types to getDisplayName() and getName().

Line 40 and Line 44 currently rely on inference; this file’s TS guideline requires explicit return types.

Suggested fix
-  getDisplayName() {
+  getDisplayName(): ChainAdapterDisplayName {
     return ChainAdapterDisplayName.Tempo
   }

-  getName() {
+  getName(): string {
     return 'Tempo'
   }

As per coding guidelines, "ALWAYS use explicit types for function parameters and return values in TypeScript."

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

In `@packages/chain-adapters/src/evm/tempo/TempoChainAdapter.ts` around lines 40 -
45, Both getDisplayName() and getName() lack explicit return types; update their
signatures to include explicit returns: set getDisplayName():
ChainAdapterDisplayName and getName(): string, adjusting the method declarations
in TempoChainAdapter to use these return types so they conform to the project's
TypeScript guideline requiring explicit function return types.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.env:
- Line 357: The base .env leaves VITE_TEMPO_NODE_URL empty which causes
src/config.ts's unconditional config validation (the required URL for
VITE_TEMPO_NODE_URL) to fail in environments that don't override it; set a
sensible default URL in the base .env (e.g., a stable public or internal tempo
node URL or a safe noop/localhost URL) so VITE_TEMPO_NODE_URL contains a valid
URL by default and validation in src/config.ts passes when VITE_FEATURE_TEMPO is
false or when environment-specific .env files are missing.

In `@packages/utils/src/getAssetNamespaceFromChainId.ts`:
- Around line 65-66: The switch branch for KnownChainIds.TempoMainnet currently
throws an error causing runtime failures; update the case in
getAssetNamespaceFromChainId to return ASSET_NAMESPACE.erc20 (same as other EVM
chains) instead of throwing, ensuring Tempo resolves to the ERC-20 asset
namespace; locate the switch that handles KnownChainIds (including TempoMainnet)
and replace the throw Error(...) branch with a return ASSET_NAMESPACE.erc20.

---

Nitpick comments:
In `@packages/chain-adapters/src/evm/tempo/TempoChainAdapter.ts`:
- Around line 40-45: Both getDisplayName() and getName() lack explicit return
types; update their signatures to include explicit returns: set
getDisplayName(): ChainAdapterDisplayName and getName(): string, adjusting the
method declarations in TempoChainAdapter to use these return types so they
conform to the project's TypeScript guideline requiring explicit function return
types.
🪄 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: 2931fd93-34de-4de5-8d8f-e681b6b07b3f

📥 Commits

Reviewing files that changed from the base of the PR and between 043d6c2 and dc368c6.

⛔ Files ignored due to path filters (22)
  • packages/caip/src/adapters/coincap/generated/eip155_1/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_10/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_137/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_42161/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_43114/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_56/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_8453/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/solana_5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_1/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_137/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_4217/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_43114/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_56/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_8453/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/index.ts is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/solana_5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/adapter.json is excluded by !**/generated/**
  • public/generated/asset-manifest.json is excluded by !**/generated/**
  • public/generated/asset-manifest.json.br is excluded by !**/generated/**
  • public/generated/asset-manifest.json.gz is excluded by !**/*.gz, !**/generated/**
  • public/generated/generatedAssetData.json is excluded by !**/generated/**
  • public/generated/generatedAssetData.json.br is excluded by !**/generated/**
  • public/generated/generatedAssetData.json.gz is excluded by !**/*.gz, !**/generated/**
📒 Files selected for processing (62)
  • .env
  • .env.development
  • chains/tempo.json
  • headers/csps/chains/tempo.ts
  • headers/csps/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/evm/tempo/TempoChainAdapter.ts
  • packages/chain-adapters/src/evm/tempo/index.ts
  • packages/chain-adapters/src/types.ts
  • packages/contracts/src/ethersProviderSingleton.ts
  • packages/contracts/src/fallbackRpcUrls.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/native-multichain.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/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/addChain/codemods.ts
  • scripts/addChain/schema.ts
  • scripts/generateAssetData/coingecko.ts
  • scripts/generateAssetData/generateAssetData.ts
  • scripts/generateAssetData/tempo/index.ts
  • src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx
  • src/config.ts
  • src/constants/chains.ts
  • src/context/PluginProvider/PluginProvider.tsx
  • src/context/WalletProvider/WalletConnectV2/config.ts
  • 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/plugins/activePlugins.ts
  • src/plugins/tempo/index.tsx
  • src/state/migrations/index.ts
  • 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
✅ Files skipped from review due to trivial changes (23)
  • packages/caip/src/adapters/coingecko/utils.test.ts
  • src/pages/Markets/components/MarketsRow.tsx
  • src/state/slices/preferencesSlice/preferencesSlice.ts
  • packages/chain-adapters/src/evm/index.ts
  • packages/contracts/src/fallbackRpcUrls.ts
  • src/lib/account/evm.ts
  • src/constants/chains.ts
  • src/test/mocks/store.ts
  • packages/types/src/base.ts
  • packages/hdwallet-trezor/src/trezor.ts
  • scripts/generateAssetData/generateAssetData.ts
  • packages/hdwallet-vultisig/src/vultisig.ts
  • packages/hdwallet-ledger/src/ledger.ts
  • headers/csps/chains/tempo.ts
  • packages/hdwallet-core/src/wallet.ts
  • src/config.ts
  • packages/contracts/src/ethersProviderSingleton.ts
  • packages/hdwallet-native/src/ethereum.ts
  • src/state/slices/portfolioSlice/utils/index.ts
  • chains/tempo.json
  • src/lib/asset-service/service/AssetService.ts
  • packages/contracts/src/viemClient.ts
  • packages/swapper/src/swappers/RelaySwapper/constant.ts
🚧 Files skipped from review as they are similar to previous changes (26)
  • src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx
  • src/context/PluginProvider/PluginProvider.tsx
  • packages/utils/src/getNativeFeeAssetReference.ts
  • headers/csps/index.ts
  • packages/utils/src/getChainShortName.ts
  • src/state/migrations/index.ts
  • scripts/generateAssetData/tempo/index.ts
  • packages/chain-adapters/src/evm/tempo/index.ts
  • packages/hdwallet-phantom/src/phantom.ts
  • packages/hdwallet-core/src/ethereum.ts
  • src/state/slices/opportunitiesSlice/mappings.ts
  • packages/hdwallet-gridplus/src/gridplus.ts
  • packages/hdwallet-coinbase/src/coinbase.ts
  • src/lib/coingecko/utils.ts
  • src/plugins/activePlugins.ts
  • packages/hdwallet-walletconnectv2/src/walletconnectV2.ts
  • packages/hdwallet-keepkey/src/keepkey.ts
  • packages/chain-adapters/src/evm/EvmBaseAdapter.ts
  • packages/utils/src/assetData/baseAssets.ts
  • packages/hdwallet-metamask-multichain/src/native-multichain.ts
  • packages/utils/src/assetData/getBaseAsset.ts
  • packages/hdwallet-metamask-multichain/src/shapeshift-multichain.ts
  • src/context/WalletProvider/WalletConnectV2/config.ts
  • src/plugins/tempo/index.tsx
  • packages/chain-adapters/src/types.ts
  • packages/caip/src/constants.ts

@gomesalexandre
Copy link
Contributor Author

qabot rerun with a less derp Tempo fixture: https://qabot-kappa.vercel.app/runs/3a63967e-92ec-4208-9455-0d343015b20c

What this fixture now checks:

  • Tempo shows in chain picker and is actually selectable
  • Tempo native asset row/icon render sanely
  • Tempo popular assets are populated
  • cross-chain swap into Tempo native
  • same-chain Tempo swap

Result: failed, and not for fake reasons this time around.

Findings:

  • Opening the buy asset selector for the Tempo assertions caused the trade page to blank into an empty black screen, so I could not even validate the Tempo chain dropdown / asset list via the UI
  • Direct route to ETH on Ethereum -> USD on Tempo via /trade/eip155:1/slip44:60/eip155:4217/slip44:60/0 also blanked the page into an empty black screen
  • As a quick control, routing to ETH on Ethereum -> ETH on Base did not blank the page, so this looks Tempo-specific, not generic trade-page weirdness

Pushed the improved qabot fixture here too:

  • d0a906a24c - test: add tempo qabot regression fixture

So yeah, PR is not gucci for trade QA yet - Tempo path still looks borked.

Tempo was crashing because native fee asset resolution still treated Tempo as Ton. Fix that, hide the bogus placeholder native from trade selection, and surface pathUSD as the practical swappable/gas asset instead.

Also update the Tempo qabot regression fixture so it validates the real user flow we can actually support: Tempo discoverability, pathUSD visibility, Tempo account connect, and a small cross-chain swap into pathUSD.
@gomesalexandre
Copy link
Contributor Author

@NeOMakinG all working now ser.

qabot: https://qabot-kappa.vercel.app/runs/d99911a8-8b36-4385-9375-440bc060a681

Tackled the actual Tempo shenanigans in the loop:

  • fix Tempo native fee asset resolution so the trade flow no longer blacks out
  • hide the bogus placeholder-native Tempo asset from Trade selection
  • surface pathUSD as the practical tradeable/gas asset for Tempo discoverability
  • update the Tempo regression fixture to test the real flow: chain filter, pathUSD, Tempo account connect, and cross-chain into pathUSD

Local manual + agent-browser pass was gucci after that, then reran/reportified via qabot ☝🏽

Does what it says on the box.

- add real Tempo tradeable asset generation for usdc/pathusd
- plumb Tempo fee-token semantics through swapper + send flows
- support Tempo tx execution payloads across wallet providers
- add qabot regression coverage for cross-chain, same-chain, and self-send

Very hacky still, but at least she worky now.

Co-Authored-By: Claude <noreply@openai.com>
@gomesalexandre gomesalexandre marked this pull request as draft March 19, 2026 19:28
@gomesalexandre
Copy link
Contributor Author

@NeOMakinG moving dis back to draft for now.

Why draft:

  • functionally, Tempo is finally worky
  • code-wise, this got way gnarlier than a normal second-class evm chain PR
  • Tempo is not just another vanilla native-gas evm chain, so this ended up needing fee-token / typed-tx / send-flow shenanigans across more of the app than originally expected

So yeah, not opening this up as “simple evm chain PR is ready to merge” cap just yet.

What is gucci now:

  • cross-chain ETH -> Tempo USDC
  • same-chain USDC -> pathUSD
  • same-chain pathUSD -> USDC
  • Tempo asset/data/icon discoverability much less borked
  • Tempo send / fee semantics worky enough for the supported token flows

qabot pass:

Also updated the PR body to call out that this is still pretty hacky and not reviewed enough code-wise yet, even though the functional pass is there now.

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.

2 participants