Skip to content

feat: second-class EVM chains Tx parsing - #11426

Merged
gomesalexandre merged 33 commits into
developfrom
feat_second_class_mm
Dec 16, 2025
Merged

feat: second-class EVM chains Tx parsing#11426
gomesalexandre merged 33 commits into
developfrom
feat_second_class_mm

Conversation

@gomesalexandre

@gomesalexandre gomesalexandre commented Dec 16, 2025

Copy link
Copy Markdown
Contributor

Description

What this PR does:

  • abstracts second class EVM chains into an inherited SecondClassEvmAdapter so we (Claude) don't have to reinvent the wheel with dupes everytime, including for the below
  • Adds Tx parsing for second-class EVM chains, fetching directly from JSON-RPC and parsing into unchained-compliant shape
  • consumes said shape in useBuyActualAmountCryptoPrecision

What this doesn't do (yet!):

  • upsert Txs anywhere, though we now could.

Issue (if applicable)

closes #11419

Risk

High Risk PRs Require 2 approvals

Low

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

Testing

  • Actual buy amount is correct for Monad, Plasma, HyperEVM
  • NOTE: This does not work for internal transactions (e.g cross-chain relay swaps to native assets) and will likely require to use another strategy as a follow-up e.g Tenderly

Engineering

  • ^

Operations

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

  • ^

Screenshots (if applicable)

Summary by CodeRabbit

  • New Features

    • Added support for additional EVM-compatible networks with improved token handling and transaction parsing for those chains.
    • Buy-amount calculations now use parsed on-chain transactions for applicable second-class EVM chains.
  • Chores

    • Consolidated and simplified EVM adapter infrastructure to share common behavior across multiple chains and streamline per-chain adapters.

✏️ Tip: You can customize this high-level summary in your review settings.

gomesalexandre and others added 19 commits December 12, 2025 11:57
Updates chain-integration skill documentation to reflect that MetaMask
supports HyperEVM, Monad, and Plasma chains. Also bumps hdwallet
dependencies to local verdaccio version for testing.

Changes:
- Updated SKILL.md to document MetaMask support for second-class EVM chains
- Added clarifying notes about Ledger/Trezor support
- Bumped all hdwallet-* packages to 1.62.29-second-class-mm.0

This allows MetaMask users to import and use accounts on HyperEVM,
Monad, and Plasma when feature flags are enabled.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Updates chain-integration skill documentation and hdwallet dependencies
to enable Ledger support for HyperEVM, Monad, and Plasma.

Changes:
- Updated SKILL.md to move Ledger to supported wallet list
- Updated documentation to reflect Ledger uses Ethereum app for all EVM chains
- Bumped all hdwallet-* packages to 1.62.29-second-class-mm.1

This allows Ledger users to import and use accounts on HyperEVM,
Monad, and Plasma when feature flags are enabled.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixes the Ledger "Open Gate" prompt appearing repeatedly for HyperEVM,
Monad, and Plasma by ensuring all EVM chains validate against the
Ethereum app instead of looking for chain-specific apps.

The issue was that `getCoin()` was returning chain-specific names like
"HyperEVM", "Monad", "Plasma" which Ledger's `validateCurrentApp()`
didn't recognize. All EVM chains use the same Ethereum Ledger app, so
they should all return "Ethereum" for validation.

Changes:
- Consolidated all EVM chain cases in getCoin() to return "Ethereum"
- Includes: Ethereum, Avalanche, Optimism, BSC, Polygon, Gnosis,
  Arbitrum, Arbitrum Nova, Base, Monad, HyperEVM, and Plasma

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Refactors ledgerAppGate.ts to use isEvmChainId() instead of maintaining
an exhaustive case list of all EVM chains. This makes the code more
maintainable and automatically supports any new EVM chains added in the
future.

Benefits:
- No need to manually add each new EVM chain to the switch statements
- More maintainable - single source of truth for EVM chain detection
- Automatically works with future EVM chains (e.g., if we add Sei, Scroll, etc.)
- Cleaner, more readable code

Changes:
- Added isEvmChainId import from EvmBaseAdapter
- Refactored getLedgerAppName() to check isEvmChainId first
- Refactored getCoin() to check isEvmChainId first
- Removed 12+ explicit EVM chain cases from both functions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixes bug where HyperEVM account addresses were not displayed in:
- Ledger/Native account import UI (shows blank address)
- Send flow "from" address row (shows blank from address)

Root cause: accountIdToLabel() was missing hyperEvmChainId in its
switch statement. Monad and Plasma were present but HyperEVM was
missing, causing it to hit the default case and return empty string.

Changes:
- Added hyperEvmChainId import from @shapeshiftoss/caip
- Added hyperEvmChainId case to accountIdToLabel() switch statement

This makes HyperEVM addresses display correctly using middleEllipsis()
formatting, consistent with all other EVM chains.

Fixes: #11393 (partial - addresses Native wallet send flow issue)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Updates chain-integration skill documentation and hdwallet dependencies
to enable Trezor support for HyperEVM, Monad, and Plasma.

Changes:
- Updated SKILL.md to move Trezor to supported wallet list
- Updated documentation to reflect Trezor uses Ethereum app for all EVM chains
- Bumped all hdwallet-* packages to 1.62.29-second-class-mm.2

This allows Trezor users to import and use accounts on HyperEVM,
Monad, and Plasma when feature flags are enabled.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Updates chain-integration skill documentation and hdwallet dependencies
to enable WalletConnect V2 support for HyperEVM, Monad, and Plasma.

Changes:
- Updated SKILL.md to move WalletConnect V2 to supported wallet list
- Added note that WalletConnect V2 is chain-agnostic
- Bumped all hdwallet-* packages to 1.62.29-second-class-mm.3

This allows WalletConnect V2 users to connect wallets and use accounts
on HyperEVM, Monad, and Plasma when feature flags are enabled.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Adds `verifyLedgerAppOpen` call to Tron chain adapter's `getAddress` method to prompt users to open the Tron app on their Ledger device before attempting to derive addresses. This matches the pattern used in other chain adapters like Solana.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Adds Sui to the list of supported chains in the ledger app gate validation functions. This ensures that when users try to interact with Sui using a Ledger hardware wallet, the app will properly prompt them to open the Sui app on their device.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Dec 16, 2025

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a new SecondClassEvmAdapter abstraction for non-standard EVM chains, reworks several EVM chain adapters (HyperEVM, Monad, Plasma) to extend it, exposes TokenInfo and related types, and updates a hook to fetch actual buy amounts from second-class chain transaction parsing.

Changes

Cohort / File(s) Change Summary
Skill Documentation
.claude/skills/chain-integration/SKILL.md
Replaced EVM guidance with a SecondClassEvmAdapter-based path, updated non-EVM guidance and file path examples.
SecondClassEvmAdapter Foundation
packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
New abstract adapter: TokenInfo type, multicall token-balance batching, gas/fee estimation, broadcast wrapper, tx parsing, and exported types (SecondClassEvmAdapterArgs, TokenInfo, SecondClassEvmAdapter).
EVM Chain Adapters Migration
packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts, packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts, packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
Changed base class from EvmBaseAdapter to SecondClassEvmAdapter; removed local provider/multicall/token/gas/broadcast/parse implementations; simplified constructors; re-export TokenInfo.
EVM Index Exports
packages/chain-adapters/src/evm/index.ts
Re-exports SecondClassEvmAdapter, SecondClassEvmAdapterArgs, and TokenInfo.
Frontend Hook
src/hooks/useActualBuyAmountCryptoPrecision.ts
Added a useQuery to parse second-class chain transactions via chain adapter to derive actual buy amounts; integrated fallback into buy-amount precision calculation.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant Adapter as SecondClassEvmAdapter
    participant Provider as JsonRpcProvider
    participant Multicall as Multicall Contract
    participant Queue as Request Queue

    Client->>Adapter: getAccount(pubkey)
    activate Adapter
    Adapter->>Provider: getBalance(pubkey) & getTransactionCount(pubkey) [parallel]
    Provider-->>Adapter: native balance, nonce

    alt knownTokens present
        Adapter->>Adapter: getTokenBalancesMulticall(pubkey, tokens)
        Adapter->>Queue: enqueue multicall batch
        Queue->>Multicall: aggregate3(calls)
        Multicall-->>Queue: multicall results
        Queue-->>Adapter: decoded token balances
    else multicall fails
        Adapter->>Provider: balanceOf(token) [iterative]
        Provider-->>Adapter: token balances
    end

    Adapter-->>Client: Account {chainId, assetId, nonce, tokenBalances}
    deactivate Adapter
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Review focus:
    • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts — multicall batching, fallback logic, viem parsing, and error translation.
    • Migrated adapters (hyperevm/monad/plasma) — ensure correct superclass initialization and exported TokenInfo usage.
    • packages/chain-adapters/src/evm/index.ts — verify re-exports and no export collisions.
    • src/hooks/useActualBuyAmountCryptoPrecision.ts — query gating, integration into existing memoized calculation, and error-tolerant behavior.

Possibly related PRs

Suggested reviewers

  • NeOMakinG

Poem

🐰 I hopped through multicalls, tiny and spry,

Batching tokens beneath the sky,
Adapters trimmed light, exports set new,
Buy amounts found where old bugs flew,
A twitch, a sniff, the chains hop by.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: second-class EVM chains Tx parsing' clearly and concisely summarizes the primary change: implementing transaction parsing for second-class EVM chains via the new SecondClassEvmAdapter.
Linked Issues check ✅ Passed The PR successfully implements transaction parsing for Plasma, HyperEVM, and Monad chains (linked issue #11419), enabling correct actual buy amount computation in notifications via the new SecondClassEvmAdapter and useBuyActualAmountCryptoPrecision integration.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing second-class EVM transaction parsing: SecondClassEvmAdapter abstraction, chain adapter updates, and integration into buy amount calculation. No unrelated refactoring or out-of-scope modifications are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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_second_class_mm

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.

gomesalexandre and others added 2 commits December 16, 2025 14:05
- Use viem for transaction fetching and event parsing
- Parse ERC-20 Transfer events from transaction receipts
- Add react-query hook in useActualBuyAmountCryptoPrecision for second-class chains
- Use isAddressEqual for address comparisons
- Immutable transfer computation pattern

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
… ci]

- Use isSend/isReceive vernacular
- Cache getAddress calls to avoid duplicates
- Extract status and fee computation to consts
- Rename unchainedTx to parsedTx for clarity

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This was referenced Dec 16, 2025
@gomesalexandre gomesalexandre changed the title feat: second-class chains Tx parsing feat: second-class EVM chains Tx parsing Dec 16, 2025
- Extract 760 lines of duplicate code into SecondClassEvmAdapter
- HyperEvmChainAdapter: 547→58 lines (89% reduction)
- MonadChainAdapter: 387→58 lines (85% reduction)
- PlasmaChainAdapter: 378→58 lines (85% reduction)
- parseTx now works for all 3 chains automatically
- Future second-class EVM chains only need ~50 lines

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
gomesalexandre and others added 6 commits December 16, 2025 15:02
…p ci]

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Simplify EVM chain adapter instructions
- Highlight that EVM chains now only need ~50 lines
- Explain SecondClassEvmAdapter benefits
- Fix Hex type for txHash

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…p ci]

- Log swap state (buy vs sell tx/chain/account)
- Log adapter retrieval and type
- Log transaction fetching from RPC
- Log Transfer event parsing
- Log token matching from knownTokens
- Log final transfer search results

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@gomesalexandre
gomesalexandre marked this pull request as ready for review December 16, 2025 13:11
@gomesalexandre
gomesalexandre requested a review from a team as a code owner December 16, 2025 13:11

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (4)
packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts (1)

44-46: getName() deviates from established pattern.

Based on learnings, the getName() method in chain adapters should use the enum reverse-lookup pattern for consistency with other adapters (Bitcoin, Ethereum, Litecoin, etc.):

const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.HyperEvm)
return Object.keys(ChainAdapterDisplayName)[enumIndex]

Current implementation returns a hardcoded string which may diverge from the enum key if renamed.

packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts (3)

57-72: Consider type-safe alternatives for dummy dependencies.

The as any casts for dummyParser and providers work but circumvent type safety. Since the parent class requires these but second-class chains don't use them, consider:

  1. Making these optional in EvmBaseAdapter if feasible
  2. Using unknown with explicit assertions
  3. Documenting why these are intentionally stubbed

This is low priority given the pattern is contained to the constructor.


195-197: Empty catch block silently swallows decode errors.

Per coding guidelines, exceptions should not be silently caught and ignored. Consider logging the decode failure for debugging:

        } catch {
+         console.warn(`[${this.getName()}] Failed to decode balance for token ${token.contractAddress}`)
          return null
        }

This helps diagnose issues with malformed return data from non-standard ERC20 implementations.


228-230: Silent catch block in fallback path.

Same issue as the multicall batch - consider adding a warning log for debugging failed individual balance fetches.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f0c198a and 05ce32c.

📒 Files selected for processing (7)
  • .claude/skills/chain-integration/SKILL.md (2 hunks)
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts (1 hunks)
  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts (3 hunks)
  • packages/chain-adapters/src/evm/index.ts (1 hunks)
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts (3 hunks)
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts (3 hunks)
  • src/hooks/useActualBuyAmountCryptoPrecision.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Never assume a library is available - always check imports/package.json first
Prefer composition over inheritance
Write self-documenting code with clear variable and function names
Keep functions small and focused on a single responsibility
Avoid deep nesting - use early returns instead
Prefer procedural and easy to understand code
Never expose, log, or commit secrets, API keys, or credentials
Validate all inputs, especially user inputs
Handle errors gracefully with meaningful messages
Don't silently catch and ignore exceptions
Log errors appropriately for debugging
Provide fallback behavior when possible
Use appropriate data structures for the task
Never add code comments unless explicitly requested
When modifying code, do not add comments that reference previous implementations or explain what changed. Comments should only describe the current logic and functionality.
Use meaningful names for branches, variables, and functions
Always run yarn lint --fix and yarn type-check after making changes
Avoid let variable assignments - prefer const with inline IIFE switch statements or extract to functions for conditional logic

Files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid useEffect where practical - use it only when necessary and following best practices
Avoid 'any' types - use specific type annotations instead
For default values with user overrides, use computed values (useMemo) instead of useEffect - pattern: userSelected ?? smartDefault ?? fallback
When function parameters are unused due to interface requirements, refactor the interface or implementation to remove them rather than prefixing with underscore
Sanitize data before displaying to prevent XSS
Memoize aggressively - wrap component variables in useMemo and callbacks in useCallback where possible
For static JSX icon elements (e.g., <TbCopy />) that don't depend on state/props, define them as constants outside the component to avoid re-renders instead of using useMemo
Account for light/dark mode using useColorModeValue hook
Account for responsive mobile designs in all UI components
When applying styles, use the existing standards and conventions of the codebase
Use Chakra UI components and conventions
All copy/text must use translation keys - never hardcode strings
Use the translation hook: useTranslate() from react-polyglot
Use useFeatureFlag('FlagName') hook to access feature flag values in components
Prefer type over interface for type definitions
Use strict typing - avoid any
Use Nominal types for domain identifiers (e.g., WalletId, AccountId)
Import types from @shapeshiftoss/caip for chain/account/asset IDs
Use useAppSelector for Redux state
Use useAppDispatch for Redux actions
Memoize expensive computations with useMemo
Memoize callbacks with useCallback

**/*.{ts,tsx}: Use Result<T, E> pattern for error handling in swappers and APIs; ALWAYS use Ok() and Err() from @sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from @shapeshiftoss/errors with meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...

Files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*.{js,jsx,ts,tsx}: Use camelCase for variables, functions, and methods with descriptive names that explain the purpose
Use verb prefixes for functions that perform actions (e.g., fetch, validate, execute, update, calculate)
Use UPPER_SNAKE_CASE for constants and configuration values with descriptive names
Use handle prefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names with is, has, can, should prefixes
Use named exports for components, functions, and utilities instead of default exports
Use descriptive import names and avoid renaming imports unless necessary
Avoid non-descriptive variable names like data, item, obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names like fn, func, or callback

Files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
🧠 Learnings (28)
📓 Common learnings
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:0-0
Timestamp: 2025-09-12T13:44:17.019Z
Learning: gomesalexandre prefers letting chain adapter errors throw naturally in useSimulateEvmTransaction rather than adding explicit error handling for missing adapters, consistent with his fail-fast approach and dismissal of defensive validation as "stale" in WalletConnect transaction simulation flows.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Reuse executeEvmTransaction utility for EVM-based swappers instead of implementing custom transaction execution
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.
📚 Learning: 2025-12-04T22:57:50.850Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 11290
File: packages/chain-adapters/src/utxo/zcash/ZcashChainAdapter.ts:48-51
Timestamp: 2025-12-04T22:57:50.850Z
Learning: In packages/chain-adapters/src/**/*ChainAdapter.ts files, the getName() method uses the pattern `const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.XXX); return Object.keys(ChainAdapterDisplayName)[enumIndex]` to reverse-lookup the enum key from its value. This is the established pattern used consistently across almost all chain adapters (Bitcoin, Ethereum, Litecoin, Dogecoin, Polygon, Arbitrum, Cosmos, etc.) and should be preserved for consistency when adding new chain adapters.

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/**/*.ts : Use TypeScript with explicit types (e.g., SupportedChainIds) for all code in the Swapper system

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Reuse executeEvmTransaction utility for EVM-based swappers instead of implementing custom transaction execution

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-09-12T13:44:17.019Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:0-0
Timestamp: 2025-09-12T13:44:17.019Z
Learning: gomesalexandre prefers letting chain adapter errors throw naturally in useSimulateEvmTransaction rather than adding explicit error handling for missing adapters, consistent with his fail-fast approach and dismissal of defensive validation as "stale" in WalletConnect transaction simulation flows.

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-11-12T12:49:17.895Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts:109-125
Timestamp: 2025-11-12T12:49:17.895Z
Learning: In packages/chain-adapters/src/evm/utils.ts, the getErc20Data function already includes a guard that returns an empty string when contractAddress is undefined (line 8: `if (!contractAddress) return ''`). This built-in handling means callers don't need to conditionally invoke getErc20Data—it safely handles both ERC20 tokens and native assets.

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-10-23T14:27:19.073Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10857
File: src/plugins/walletConnectToDapps/eventsManager/useWalletConnectEventsHandler.ts:101-104
Timestamp: 2025-10-23T14:27:19.073Z
Learning: In WalletConnect wallet_switchEthereumChain and wallet_addEthereumChain requests, the chainId parameter is always present as per the protocol spec. Type guards checking for missing chainId in these handlers (like `if (!evmNetworkIdHex) return`) are solely for TypeScript compiler satisfaction, not real runtime edge cases.

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Import types from `shapeshiftoss/caip` for chain/account/asset IDs

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-08-17T21:53:03.806Z
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10290
File: scripts/generateAssetData/color-map.json:41-47
Timestamp: 2025-08-17T21:53:03.806Z
Learning: In the ShapeShift web codebase, native assets (using CAIP-19 slip44 namespace like eip155:1/slip44:60, bip122:.../slip44:..., cosmos:.../slip44:...) are manually hardcoded and not generated via the automated asset generation script. Only ERC20/BEP20 tokens go through the asset generation process. The validation scripts should only validate generated assets, not manually added native assets.

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/utils/constants.ts : Define supported chain IDs for each swapper in utils/constants.ts with both 'sell' and 'buy' properties following the pattern: SupportedChainIds type

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/index.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Implement filterBuyAssetsBySellAssetId method to filter assets by supported chain IDs in the buy property

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-08-05T23:36:13.214Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10187
File: src/state/slices/preferencesSlice/selectors.ts:21-25
Timestamp: 2025-08-05T23:36:13.214Z
Learning: The AssetId type from 'shapeshiftoss/caip' package is a string type alias, so it can be used directly as a return type for cache key resolvers in re-reselect selectors without needing explicit string conversion.

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Implement filterAssetIdsBySellable method to filter assets by supported chain IDs in the sell property

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-09-04T17:29:59.479Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx:28-33
Timestamp: 2025-09-04T17:29:59.479Z
Learning: In shapeshift/web, the useGetPopularAssetsQuery function in src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx intentionally uses primaryAssets[assetId] instead of falling back to assets[assetId]. The design distributes primary assets across chains by iterating through their related assets and adding the primary asset to each related asset's chain. This ensures primary assets appear in all chains where they have related assets, supporting the grouped asset system.

Applied to files:

  • packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts
  • src/hooks/useActualBuyAmountCryptoPrecision.ts
  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
  • packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts
📚 Learning: 2025-09-12T10:15:10.389Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP712MessageDisplay.tsx:133-137
Timestamp: 2025-09-12T10:15:10.389Z
Learning: gomesalexandre has identified that EIP-712 domain chainId should be preferred over request context chainId for accuracy in WalletConnect dApps structured signing flows. The domain chainId from the parsed message is more specific and accurate than the general request context, especially for asset resolution and network-specific operations.

Applied to files:

  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-08-26T19:04:38.672Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10369
File: packages/chain-adapters/src/cosmossdk/CosmosSdkBaseAdapter.ts:167-176
Timestamp: 2025-08-26T19:04:38.672Z
Learning: In packages/chain-adapters/src/cosmossdk/CosmosSdkBaseAdapter.ts, when processing assets from data.assets.reduce(), the team prefers using empty catch blocks to gracefully skip any assets that fail processing, rather than specific error type handling, to avoid useless noise and ensure robust asset filtering.

Applied to files:

  • .claude/skills/chain-integration/SKILL.md
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-11-19T16:59:50.569Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11012
File: src/context/WalletProvider/Vultisig/components/Connect.tsx:24-59
Timestamp: 2025-11-19T16:59:50.569Z
Learning: In src/context/WalletProvider/*/components/Connect.tsx files across the ShapeShift web codebase, the established pattern for handling null/undefined adapter from getAdapter() is to simply check `if (adapter) { ... }` without an else clause. All wallet Connect components (Coinbase, Keplr, Phantom, Ledger, MetaMask, WalletConnectV2, KeepKey, Vultisig) follow this pattern—they reset loading state after the if block but do not show error messages when adapter is null. This is an intentional design decision and should be maintained for consistency.

Applied to files:

  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-11-03T22:31:30.786Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10985
File: packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeQuote/getPortalsTradeQuote.ts:0-0
Timestamp: 2025-11-03T22:31:30.786Z
Learning: In packages/swapper/src/swappers/PortalsSwapper, the rate and quote files intentionally use different approaches for calculating buyAmountBeforeSlippageCryptoBaseUnit: getPortalsTradeRate.tsx uses minOutputAmount / (1 - buffer) for conservative estimates, while getPortalsTradeQuote.ts uses outputAmount / (1 - buffer) for final quote display. This difference is validated by on-chain simulation testing and is intentional.

Applied to files:

  • src/hooks/useActualBuyAmountCryptoPrecision.ts
📚 Learning: 2025-10-21T17:11:18.087Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10871
File: src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx:426-428
Timestamp: 2025-10-21T17:11:18.087Z
Learning: In src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx, within the handleInputChange function, use .toFixed() without arguments (not .toString()) when converting BigNumber amounts for input field synchronization. This avoids exponential notation in the input while preserving precision for presentational components like <Amount.Crypto /> and <Amount.Fiat /> to format appropriately.

Applied to files:

  • src/hooks/useActualBuyAmountCryptoPrecision.ts
📚 Learning: 2025-09-12T10:21:26.693Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP712MessageDisplay.tsx:0-0
Timestamp: 2025-09-12T10:21:26.693Z
Learning: gomesalexandre explained that in WalletConnect V2, the request context chainId comes from params?.chainId following CAIP2 standards, making both the request params chainId and EIP-712 domain chainId equally reliable sources. He considers both approaches trustworthy ("both gucci") for WalletConnect dApps integration.

Applied to files:

  • src/hooks/useActualBuyAmountCryptoPrecision.ts
📚 Learning: 2025-08-22T15:07:18.021Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10326
File: src/hooks/useActionCenterSubscribers/useThorchainLpActionSubscriber.tsx:37-41
Timestamp: 2025-08-22T15:07:18.021Z
Learning: In src/hooks/useActionCenterSubscribers/useThorchainLpActionSubscriber.tsx, kaladinlight prefers not to await the upsertBasePortfolio call in the Base chain handling block, indicating intentional fire-and-forget behavior for Base portfolio upserts in the THORChain LP completion flow.

Applied to files:

  • src/hooks/useActualBuyAmountCryptoPrecision.ts
📚 Learning: 2025-08-04T16:02:27.360Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10171
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandedStepperSteps.tsx:458-458
Timestamp: 2025-08-04T16:02:27.360Z
Learning: In multi-hop swap transactions, last hop sell transactions might not be detected by the swapper (unlike buy transactions which are always known immediately). The conditional stepSource logic for last hop buy transactions (`isLastHopSellTxSeen ? stepSource : undefined`) serves as defensive programming for future multi-hop support with intermediate chains, even though multi-hop functionality is not currently supported in production.

Applied to files:

  • src/hooks/useActualBuyAmountCryptoPrecision.ts
📚 Learning: 2025-08-11T09:46:41.060Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10219
File: src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx:167-172
Timestamp: 2025-08-11T09:46:41.060Z
Learning: In the shapeshift/web repository, the display cache logic for trade quotes (using `selectUserAvailableTradeQuotes` and `selectUserUnavailableTradeQuotes`) is intentionally kept the same between `TradeInput.tsx` and `TradeQuotes.tsx` components. The `hasQuotes` computation in `TradeInput.tsx` uses these display cache selectors by design, matching the pattern used in `TradeQuotes.tsx`.

Applied to files:

  • src/hooks/useActualBuyAmountCryptoPrecision.ts
📚 Learning: 2025-07-24T11:07:20.536Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10073
File: src/features/defi/providers/fox-farming/components/FoxFarmingManager/Claim/Claim.tsx:77-84
Timestamp: 2025-07-24T11:07:20.536Z
Learning: In fox farming components, the `opportunity?.rewardsCryptoBaseUnit?.amounts` property has a well-defined type signature that is always an array (never undefined), but can be empty: `readonly [] | readonly [string, string, string] | readonly [string, string] | readonly [string]`. Using optional chaining on the `amounts` property itself is unnecessary since it's always defined, though accessing `amounts[0]` on an empty array returns undefined which bnOrZero() handles safely.

Applied to files:

  • src/hooks/useActualBuyAmountCryptoPrecision.ts
📚 Learning: 2025-09-12T12:04:59.556Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/SendTransactionContent.tsx:0-0
Timestamp: 2025-09-12T12:04:59.556Z
Learning: The ShapeShift codebase's fromBaseUnit function correctly handles hex strings (like WalletConnect transaction.value) without manual conversion because bnOrZero -> bn -> new BigNumber() automatically detects and parses hex strings starting with "0x". gomesalexandre confirmed this with concrete evidence showing hex value 0x176d1c49189db correctly converts to 0.000412118294825435 ETH.

Applied to files:

  • src/hooks/useActualBuyAmountCryptoPrecision.ts
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/index.ts : Export unique functions and types from packages/swapper/src/index.ts only if needed for external consumption

Applied to files:

  • packages/chain-adapters/src/evm/index.ts
📚 Learning: 2025-08-14T17:54:32.563Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/ReusableLpStatus.tsx:97-108
Timestamp: 2025-08-14T17:54:32.563Z
Learning: In ReusableLpStatus component (src/pages/ThorChainLP/components/ReusableLpStatus/ReusableLpStatus.tsx), the txAssets dependency is stable from first render because poolAsset, baseAsset, actionSide, and action are all defined first render, making the current txAssetsStatuses initialization pattern safe without needing useEffect synchronization.

Applied to files:

  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
📚 Learning: 2025-10-15T15:57:39.956Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10810
File: src/plugins/walletConnectToDapps/utils/tenderly/index.ts:212-0
Timestamp: 2025-10-15T15:57:39.956Z
Learning: gomesalexandre uses discriminated union patterns (e.g., `isEIP1559 ? { max_fee_per_gas, max_priority_fee_per_gas } : { gas_price }`) in WalletConnect flows without additional validation guards, trusting that the runtime data structure ensures mutual exclusivity between EIP-1559 and legacy gas pricing fields.

Applied to files:

  • packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts
🧬 Code graph analysis (3)
src/hooks/useActualBuyAmountCryptoPrecision.ts (2)
packages/chain-adapters/src/types.ts (1)
  • TransferType (133-133)
src/constants/chains.ts (1)
  • SECOND_CLASS_CHAINS (8-14)
packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts (4)
packages/chain-adapters/src/evm/index.ts (1)
  • SecondClassEvmAdapter (3-3)
packages/types/src/base.ts (1)
  • RootBip44Params (5-9)
packages/caip/src/constants.ts (2)
  • ASSET_REFERENCE (140-165)
  • plasmaAssetId (21-21)
packages/chain-adapters/src/evm/EvmBaseAdapter.ts (1)
  • ChainAdapterArgs (95-102)
packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts (8)
packages/chain-adapters/src/evm/index.ts (2)
  • TokenInfo (4-4)
  • SecondClassEvmAdapter (3-3)
packages/caip/src/assetId/assetId.ts (2)
  • AssetId (17-17)
  • toAssetId (59-127)
packages/contracts/src/constants.ts (1)
  • MULTICALL3_CONTRACT (133-133)
packages/chain-adapters/src/evm/types.ts (1)
  • GasFeeDataEstimate (76-80)
packages/chain-adapters/src/types.ts (1)
  • FeeDataEstimate (113-117)
packages/chain-adapters/src/error/ErrorHandler.ts (1)
  • ErrorHandler (28-73)
packages/contracts/src/viemClient.ts (1)
  • viemClientByChainId (97-110)
packages/caip/src/constants.ts (1)
  • ASSET_NAMESPACE (129-138)
🔇 Additional comments (13)
.claude/skills/chain-integration/SKILL.md (1)

701-776: Documentation accurately reflects the new SecondClassEvmAdapter pattern.

The updated guidance properly documents the simplified EVM chain integration path using SecondClassEvmAdapter, which aligns with the actual implementations in HyperEVM, Monad, and Plasma adapters. The example code demonstrates the minimal ~50 line implementation pattern correctly.

packages/chain-adapters/src/evm/index.ts (1)

3-4: Clean public API surface for SecondClassEvmAdapter.

The exports properly expose the new adapter class and its associated types, enabling consumption by the chain-specific adapters (HyperEVM, Monad, Plasma) and external consumers.

src/hooks/useActualBuyAmountCryptoPrecision.ts (2)

31-63: Well-structured query for second-class chain transaction parsing.

The implementation correctly:

  • Guards execution with chain membership check via SECOND_CLASS_CHAINS.includes()
  • Uses Infinity for staleTime/gcTime since transaction data is immutable
  • Returns undefined on errors, consistent with the existing fallback pattern
  • Properly extracts the Receive transfer matching the buy asset

65-84: Correct fallback priority and dependency array.

The fallback chain properly prioritizes:

  1. swap.actualBuyAmountCryptoBaseUnit (from swap state)
  2. secondClassChainActualBuyAmount (from parsed tx for second-class chains)
  3. tx.transfers (from Redux state)

This addresses the PR objective of fixing amount discrepancies for Plasma/HyperEVM swaps.

packages/chain-adapters/src/evm/monad/MonadChainAdapter.ts (2)

22-54: Clean migration to SecondClassEvmAdapter.

The adapter correctly:

  • Extends SecondClassEvmAdapter<KnownChainIds.MonadMainnet> instead of EvmBaseAdapter
  • Passes required configuration to super() constructor
  • Maintains the public API surface (getDisplayName, getName, getType, getFeeAssetId)
  • Uses knownTokens ?? [] to provide safe default

This significantly reduces code duplication while maintaining functionality.


56-57: TokenInfo type re-export enables public API consumption.

Re-exporting TokenInfo allows consumers of this module to access the type without importing directly from SecondClassEvmAdapter, maintaining a clean public API surface consistent with HyperEVM and Plasma adapters.

packages/chain-adapters/src/evm/plasma/PlasmaChainAdapter.ts (1)

22-57: Consistent migration pattern with other second-class EVM adapters.

PlasmaChainAdapter follows the same pattern as MonadChainAdapter (and HyperEvmChainAdapter per AI summary):

  • Extends SecondClassEvmAdapter<KnownChainIds.PlasmaMainnet>
  • Passes chain-specific configuration to super()
  • Maintains identical public API surface
  • Re-exports TokenInfo type

This consistency across adapters makes the codebase easier to maintain and extend.

packages/chain-adapters/src/evm/hyperevm/HyperEvmChainAdapter.ts (1)

22-38: Clean refactor to use SecondClassEvmAdapter.

The adapter now properly delegates to SecondClassEvmAdapter, significantly reducing code duplication while maintaining the same public API surface. The constructor correctly passes all required arguments including knownTokens with a sensible default.

packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts (5)

250-254: Same fee values for all speed tiers is intentional but worth documenting.

The adapter returns identical fast, average, and slow fees, which differs from first-class chain adapters. This appears intentional for second-class chains but could benefit from a brief comment explaining why fee differentiation isn't available.


302-320: Solid broadcast implementation with sanctions checking.

The implementation correctly validates addresses against sanctions before broadcasting, handles contract interactions appropriately, and uses the established ErrorHandler pattern for error translation.


422-507: Well-structured transaction parsing logic.

The parse method correctly:

  • Identifies send/receive direction using address comparison
  • Handles both native and token transfers
  • Constructs proper assetId values using toAssetId with ERC20 namespace
  • Only includes fee for the sender
  • Handles edge case of self-transfers (both isSend and isReceive true)

322-341: Stub implementations are appropriate for second-class chains.

The unsubscribeTxs, subscribeTxs, and getTxHistory stubs return sensible defaults. The underscore-prefixed parameters indicate these are required by the interface but intentionally unused. Per PR objectives, tx history and subscription are not yet implemented for these chains.


90-93: Handle potential undefined from requestQueue.add.

PQueue.add() returns Promise<T | void> - when the queue is paused or cleared, it can return undefined. The destructuring assumes defined values.

-      const [balance, nonce] = await Promise.all([
-        this.requestQueue.add(() => this.provider.getBalance(pubkey)),
-        this.requestQueue.add(() => this.provider.getTransactionCount(pubkey)),
-      ])
+      const [balance, nonce] = await Promise.all([
+        this.requestQueue.add(() => this.provider.getBalance(pubkey)).then(b => b ?? 0n),
+        this.requestQueue.add(() => this.provider.getTransactionCount(pubkey)).then(n => n ?? 0),
+      ])

Likely an incorrect or invalid review comment.

Comment thread packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (4)
packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts (4)

118-120: Preserve error context in catch block.

The error message loses the original error details. Consider using string interpolation without wrapping to preserve stack traces.

Apply this diff:

     } catch (err) {
-      throw new Error(`Failed to get account: ${err}`)
+      throw err instanceof Error 
+        ? new Error(`Failed to get account: ${err.message}`, { cause: err })
+        : new Error(`Failed to get account: ${String(err)}`)
     }

326-332: Unused parameters with underscore prefix.

The coding guidelines state: "When function parameters are unused due to interface requirements, refactor the interface or implementation to remove them rather than prefixing with underscore." Consider whether these methods need parameters at all, or if the interface can be simplified for second-class adapters.

As per coding guidelines, consider refactoring the interface to remove unused parameters for second-class chains, or provide a comment explaining why the IChainAdapter interface requires these signatures.


343-349: Validate txHash type before casting.

Line 344 casts txHash to Hex without validation. Consider validating the format first.

   async parseTx(txHash: unknown, pubkey: string): Promise<Transaction> {
-    const hash = txHash as Hex
+    const hash = typeof txHash === 'string' && txHash.startsWith('0x') 
+      ? (txHash as Hex)
+      : (() => { throw new Error(`Invalid txHash format: ${txHash}`) })()
     const viemClient = viemClientByChainId[this.chainId]

392-392: Timestamp defaults to 0 when block is unavailable.

When block fetching fails or returns null, timestamp is set to 0, which could cause issues with transaction sorting and display. Consider using the current time as a fallback or throwing an error if timestamp is critical.

-      const timestamp = block?.timestamp ? Number(block.timestamp) : 0
+      const timestamp = block?.timestamp 
+        ? Number(block.timestamp)
+        : Math.floor(Date.now() / 1000)  // Fallback to current time
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 05ce32c and ec47899.

📒 Files selected for processing (2)
  • .claude/skills/chain-integration/SKILL.md (2 hunks)
  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Never assume a library is available - always check imports/package.json first
Prefer composition over inheritance
Write self-documenting code with clear variable and function names
Keep functions small and focused on a single responsibility
Avoid deep nesting - use early returns instead
Prefer procedural and easy to understand code
Never expose, log, or commit secrets, API keys, or credentials
Validate all inputs, especially user inputs
Handle errors gracefully with meaningful messages
Don't silently catch and ignore exceptions
Log errors appropriately for debugging
Provide fallback behavior when possible
Use appropriate data structures for the task
Never add code comments unless explicitly requested
When modifying code, do not add comments that reference previous implementations or explain what changed. Comments should only describe the current logic and functionality.
Use meaningful names for branches, variables, and functions
Always run yarn lint --fix and yarn type-check after making changes
Avoid let variable assignments - prefer const with inline IIFE switch statements or extract to functions for conditional logic

Files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid useEffect where practical - use it only when necessary and following best practices
Avoid 'any' types - use specific type annotations instead
For default values with user overrides, use computed values (useMemo) instead of useEffect - pattern: userSelected ?? smartDefault ?? fallback
When function parameters are unused due to interface requirements, refactor the interface or implementation to remove them rather than prefixing with underscore
Sanitize data before displaying to prevent XSS
Memoize aggressively - wrap component variables in useMemo and callbacks in useCallback where possible
For static JSX icon elements (e.g., <TbCopy />) that don't depend on state/props, define them as constants outside the component to avoid re-renders instead of using useMemo
Account for light/dark mode using useColorModeValue hook
Account for responsive mobile designs in all UI components
When applying styles, use the existing standards and conventions of the codebase
Use Chakra UI components and conventions
All copy/text must use translation keys - never hardcode strings
Use the translation hook: useTranslate() from react-polyglot
Use useFeatureFlag('FlagName') hook to access feature flag values in components
Prefer type over interface for type definitions
Use strict typing - avoid any
Use Nominal types for domain identifiers (e.g., WalletId, AccountId)
Import types from @shapeshiftoss/caip for chain/account/asset IDs
Use useAppSelector for Redux state
Use useAppDispatch for Redux actions
Memoize expensive computations with useMemo
Memoize callbacks with useCallback

**/*.{ts,tsx}: Use Result<T, E> pattern for error handling in swappers and APIs; ALWAYS use Ok() and Err() from @sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from @shapeshiftoss/errors with meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...

Files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*.{js,jsx,ts,tsx}: Use camelCase for variables, functions, and methods with descriptive names that explain the purpose
Use verb prefixes for functions that perform actions (e.g., fetch, validate, execute, update, calculate)
Use UPPER_SNAKE_CASE for constants and configuration values with descriptive names
Use handle prefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names with is, has, can, should prefixes
Use named exports for components, functions, and utilities instead of default exports
Use descriptive import names and avoid renaming imports unless necessary
Avoid non-descriptive variable names like data, item, obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names like fn, func, or callback

Files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
🧠 Learnings (16)
📓 Common learnings
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.
📚 Learning: 2025-11-12T12:49:17.895Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts:109-125
Timestamp: 2025-11-12T12:49:17.895Z
Learning: In packages/chain-adapters/src/evm/utils.ts, the getErc20Data function already includes a guard that returns an empty string when contractAddress is undefined (line 8: `if (!contractAddress) return ''`). This built-in handling means callers don't need to conditionally invoke getErc20Data—it safely handles both ERC20 tokens and native assets.

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-12-04T22:57:50.850Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 11290
File: packages/chain-adapters/src/utxo/zcash/ZcashChainAdapter.ts:48-51
Timestamp: 2025-12-04T22:57:50.850Z
Learning: In packages/chain-adapters/src/**/*ChainAdapter.ts files, the getName() method uses the pattern `const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.XXX); return Object.keys(ChainAdapterDisplayName)[enumIndex]` to reverse-lookup the enum key from its value. This is the established pattern used consistently across almost all chain adapters (Bitcoin, Ethereum, Litecoin, Dogecoin, Polygon, Arbitrum, Cosmos, etc.) and should be preserved for consistency when adding new chain adapters.

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/**/*.ts : Use TypeScript with explicit types (e.g., SupportedChainIds) for all code in the Swapper system

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Reuse executeEvmTransaction utility for EVM-based swappers instead of implementing custom transaction execution

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-09-12T13:44:17.019Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:0-0
Timestamp: 2025-09-12T13:44:17.019Z
Learning: gomesalexandre prefers letting chain adapter errors throw naturally in useSimulateEvmTransaction rather than adding explicit error handling for missing adapters, consistent with his fail-fast approach and dismissal of defensive validation as "stale" in WalletConnect transaction simulation flows.

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Import types from `shapeshiftoss/caip` for chain/account/asset IDs

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-08-22T12:58:26.590Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/GenericTransactionActionCard.tsx:108-111
Timestamp: 2025-08-22T12:58:26.590Z
Learning: In the RFOX GenericTransactionDisplayType flow in src/components/Layout/Header/ActionCenter/components/GenericTransactionActionCard.tsx, the txHash is always guaranteed to be present according to NeOMakinG, so defensive null checks for txLink are not needed in this context.

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-11-20T12:00:45.005Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11078
File: src/setupVitest.ts:11-15
Timestamp: 2025-11-20T12:00:45.005Z
Learning: In shapeshift/web, src/setupVitest.ts must redirect 'ethers' to 'ethers5' for shapeshiftoss/hdwallet-trezor (and -trezor-connect), same as ledger and shapeshift-multichain. Removing 'trezor' from the regex causes CI/Vitest failures due to ethers v6 vs v5 API differences.

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-12-04T11:05:01.146Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11281
File: packages/swapper/src/swappers/PortalsSwapper/utils/fetchSquidStatus.ts:98-106
Timestamp: 2025-12-04T11:05:01.146Z
Learning: In packages/swapper/src/swappers/PortalsSwapper/utils/fetchSquidStatus.ts, getSquidTrackingLink should return blockchain explorer links (using Asset.explorerTxLink) rather than API endpoints. For non-GMP Squid swaps: return source chain explorer link with sourceTxHash when pending/failed, and destination chain explorer link with destinationTxHash when confirmed.

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
📚 Learning: 2025-11-19T16:59:50.569Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11012
File: src/context/WalletProvider/Vultisig/components/Connect.tsx:24-59
Timestamp: 2025-11-19T16:59:50.569Z
Learning: In src/context/WalletProvider/*/components/Connect.tsx files across the ShapeShift web codebase, the established pattern for handling null/undefined adapter from getAdapter() is to simply check `if (adapter) { ... }` without an else clause. All wallet Connect components (Coinbase, Keplr, Phantom, Ledger, MetaMask, WalletConnectV2, KeepKey, Vultisig) follow this pattern—they reset loading state after the if block but do not show error messages when adapter is null. This is an intentional design decision and should be maintained for consistency.

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Implement filterBuyAssetsBySellAssetId method to filter assets by supported chain IDs in the buy property

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-10-23T14:27:19.073Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10857
File: src/plugins/walletConnectToDapps/eventsManager/useWalletConnectEventsHandler.ts:101-104
Timestamp: 2025-10-23T14:27:19.073Z
Learning: In WalletConnect wallet_switchEthereumChain and wallet_addEthereumChain requests, the chainId parameter is always present as per the protocol spec. Type guards checking for missing chainId in these handlers (like `if (!evmNetworkIdHex) return`) are solely for TypeScript compiler satisfaction, not real runtime edge cases.

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Implement filterAssetIdsBySellable method to filter assets by supported chain IDs in the sell property

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/utils/constants.ts : Define supported chain IDs for each swapper in utils/constants.ts with both 'sell' and 'buy' properties following the pattern: SupportedChainIds type

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
📚 Learning: 2025-08-26T19:04:38.672Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10369
File: packages/chain-adapters/src/cosmossdk/CosmosSdkBaseAdapter.ts:167-176
Timestamp: 2025-08-26T19:04:38.672Z
Learning: In packages/chain-adapters/src/cosmossdk/CosmosSdkBaseAdapter.ts, when processing assets from data.assets.reduce(), the team prefers using empty catch blocks to gracefully skip any assets that fail processing, rather than specific error type handling, to avoid useless noise and ensure robust asset filtering.

Applied to files:

  • packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts
  • .claude/skills/chain-integration/SKILL.md
🔇 Additional comments (8)
packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts (7)

1-31: LGTM: Clean imports and reasonable constants.

The minimal ERC20 ABI and batch size of 500 are appropriate for the multicall balance fetching pattern.


33-48: LGTM: Well-defined types with clear property names.

The TokenInfo and SecondClassEvmAdapterArgs types follow coding guidelines with explicit types and descriptive property names.


123-235: LGTM: Robust token balance fetching with fallback strategy.

The multicall batching with fallback to individual calls is well-designed. Empty catch blocks at lines 195, 196, 228, 229 intentionally skip failing tokens, following the team's preference for graceful degradation.


237-300: LGTM: Handles both legacy and EIP-1559 gas pricing.

The implementation correctly handles optional maxFeePerGas/maxPriorityFeePerGas for EIP-1559 chains while falling back to gasPrice for legacy chains. Returning identical fast/average/slow estimates is acceptable for the "poor man's" approach.


302-320: LGTM: Proper sanctions validation before broadcasting.

The implementation correctly validates both sender and receiver addresses (when not a contract interaction) using parallel checks, and uses ErrorHandler for consistent error translation.


361-363: ✅ Past bug is fixed: Block hash correctly retrieved from receipt.

The past review comment at lines 352-356 flagged that getBlock was called with transaction hash instead of block hash. The current code correctly uses receipt.blockHash, so this issue is resolved.


57-86: Verify rate limiting configuration is appropriate for target chains.

The PQueue configuration limits requests to one every 50ms (20 requests/second), which is very conservative. Confirm this is appropriate for the public RPC endpoints of all target second-class chains (Monad, Plasma, HyperEVM), as it may cause slow balance updates when fetching many token balances.

#!/bin/bash
# Check if other adapters use different rate limiting configurations
rg -A3 "new PQueue" packages/chain-adapters/src/
.claude/skills/chain-integration/SKILL.md (1)

701-776: LGTM: Accurate documentation of SecondClassEvmAdapter pattern.

The documentation correctly describes the simplified EVM chain integration pattern and provides a complete, accurate code example. The listed features (lines 768-774) match what SecondClassEvmAdapter actually provides.

Consider adding a note about limitations:

  • Transaction history/subscriptions are no-ops (intentional for "poor man's" approach)
  • Same fee estimates for fast/average/slow
  • Timestamp may be 0 if block fetch fails
  • Relies on public RPC, subject to rate limits

Based on learnings, avoid adding comments to code about these limitations, but documentation sections can benefit from this context.

Comment thread packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts

@NeOMakinG NeOMakinG left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

https://jam.dev/c/1eea4f21-2b7f-42f5-ad57-623b7cb8dfe8

All amounts are sane now!

Love the new shared adapter, will be way simpler now to integrate a new EVM chain as a second class!

Comment thread src/hooks/useActualBuyAmountCryptoPrecision.ts
@gomesalexandre
gomesalexandre merged commit 4c5df99 into develop Dec 16, 2025
4 checks passed
@gomesalexandre
gomesalexandre deleted the feat_second_class_mm branch December 16, 2025 16:11
capy-ai Bot pushed a commit that referenced this pull request Dec 17, 2025
- Implemented parseTx method in SuiChainAdapter
- Fetches transaction details using getTransactionBlock API
- Parses balance changes to determine transfers
- Handles both native SUI and token transfers
- Maps coinType to assetId with proper normalization
- Returns Transaction object compatible with useActualBuyAmountCryptoPrecision hook
- Similar to EVM implementation in PR #11426 but without abstraction

Closes #11427

Co-authored-by: Capy <capy@capy.ai>
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.

Plasma and Hype swaps shows different amounts in notification centre vs the txid

2 participants