feat: migrate addressable over to hypelabs - #11420
Conversation
📝 WalkthroughWalkthroughThis PR replaces the Addressable pixel integration with a HypeLab pixel across the app: env vars, CSP, config, pixels, window typings, a HypeLab wrapper, and telemetry hooks (wallet connect, trade confirm, trade success) are updated to use HypeLab. Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
src/pixels/hypelab.ts (2)
2-6: Simplify boolean normalization and validate propertySlug.Line 5 uses
String(enabledRaw).toLowerCase()which is unnecessarily defensive since environment variables are already strings. Additionally, line 6 exits if propertySlug is missing but doesn't validate its format. Per the PR objectives, the slug should be4793fe16ca.Apply this diff to simplify and add validation:
- const enabledRaw = import.meta.env.VITE_ENABLE_HYPELAB - const propertySlug = import.meta.env.VITE_HYPELAB_PROPERTY_SLUG - - const enabled = String(enabledRaw).toLowerCase() === 'true' - if (!enabled || !propertySlug) return + const enabled = import.meta.env.VITE_ENABLE_HYPELAB === 'true' + const propertySlug = import.meta.env.VITE_HYPELAB_PROPERTY_SLUG + + if (!enabled || !propertySlug) returnOptionally, add a console warning for invalid slug:
if (propertySlug !== '4793fe16ca') { console.warn(`Unexpected HypeLab property slug: ${propertySlug}`) }
37-44: Simplify script insertion logic.The multiple fallback paths (insertBefore → head.appendChild → documentElement.appendChild) are overly defensive. Modern browsers always have
document.headavailable, and the standard approach is to simply append to the head.Apply this diff to simplify:
- const firstScript = document.getElementsByTagName('script')[0] - if (firstScript && firstScript.parentNode) { - firstScript.parentNode.insertBefore(script, firstScript) - } else if (document.head) { - document.head.appendChild(script) - } else { - document.documentElement.appendChild(script) - } + document.head.appendChild(script)src/lib/hypelab/hypelabSingleton.ts (1)
7-16: LGTM with a minor suggestion.The validation logic properly guards against missing HypeLab integration. The duplicate feature flag check (also in
src/pixels/hypelab.tsline 5) is acceptable for safety.Consider extracting the return type to a shared type definition to ensure consistency with
window.d.ts:export type HypeLabAnalytics = { logEvent: (event: string) => void } export const getHypeLab = (): HypeLabAnalytics | undefined => { // ... }
📜 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.
📒 Files selected for processing (13)
.env(1 hunks).env.production(1 hunks)headers/csps/hypelab.ts(1 hunks)headers/csps/index.ts(2 hunks)src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx(3 hunks)src/config.ts(1 hunks)src/index.tsx(1 hunks)src/lib/hypelab/hypelabSingleton.ts(1 hunks)src/pixels/addressable.ts(0 hunks)src/pixels/hypelab.ts(1 hunks)src/state/slices/portfolioSlice/portfolioSlice.ts(2 hunks)src/vite-env.d.ts(2 hunks)src/window.d.ts(1 hunks)
💤 Files with no reviewable changes (1)
- src/pixels/addressable.ts
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{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 runyarn lint --fixandyarn type-checkafter making changes
Avoidletvariable assignments - preferconstwith inline IIFE switch statements or extract to functions for conditional logic
Files:
src/vite-env.d.tssrc/index.tsxsrc/state/slices/portfolioSlice/portfolioSlice.tssrc/pixels/hypelab.tsheaders/csps/hypelab.tsheaders/csps/index.tssrc/config.tssrc/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsxsrc/lib/hypelab/hypelabSingleton.tssrc/window.d.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 inuseMemoand callbacks inuseCallbackwhere 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 usinguseColorModeValuehook
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()fromreact-polyglot
UseuseFeatureFlag('FlagName')hook to access feature flag values in components
Prefertypeoverinterfacefor type definitions
Use strict typing - avoidany
UseNominaltypes for domain identifiers (e.g.,WalletId,AccountId)
Import types from@shapeshiftoss/caipfor chain/account/asset IDs
UseuseAppSelectorfor Redux state
UseuseAppDispatchfor Redux actions
Memoize expensive computations withuseMemo
Memoize callbacks withuseCallback
**/*.{ts,tsx}: UseResult<T, E>pattern for error handling in swappers and APIs; ALWAYS useOk()andErr()from@sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from@shapeshiftoss/errorswith meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...
Files:
src/vite-env.d.tssrc/index.tsxsrc/state/slices/portfolioSlice/portfolioSlice.tssrc/pixels/hypelab.tsheaders/csps/hypelab.tsheaders/csps/index.tssrc/config.tssrc/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsxsrc/lib/hypelab/hypelabSingleton.tssrc/window.d.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
Usehandleprefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names withis,has,can,shouldprefixes
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 likedata,item,obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names likefn,func, orcallback
Files:
src/vite-env.d.tssrc/index.tsxsrc/state/slices/portfolioSlice/portfolioSlice.tssrc/pixels/hypelab.tsheaders/csps/hypelab.tsheaders/csps/index.tssrc/config.tssrc/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsxsrc/lib/hypelab/hypelabSingleton.tssrc/window.d.ts
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
**/*.{tsx,jsx}: ALWAYS wrap React components in error boundaries and provide user-friendly fallback components with error logging
ALWAYS useuseErrorToasthook for displaying errors with translated error messages and handle different error types appropriatelyUse PascalCase for React component names and match the component name to the file name
Files:
src/index.tsxsrc/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)
**/*.{jsx,tsx}: ALWAYS useuseMemofor expensive computations, object/array creations, and filtered data
ALWAYS useuseMemofor derived values and computed properties
ALWAYS useuseMemofor conditional values and simple transformations
ALWAYS useuseCallbackfor event handlers and functions passed as props
ALWAYS useuseCallbackfor any function that could be passed as a prop or dependency
ALWAYS include all dependencies inuseEffect,useMemo,useCallbackdependency arrays
NEVER use// eslint-disable-next-line react-hooks/exhaustive-depsunless absolutely necessary, and ALWAYS explain why dependencies are excluded if using eslint disable
ALWAYS use named exports for components; NEVER use default exports for components
KEEP component files under 200 lines when possible; BREAK DOWN large components into smaller, reusable pieces
EXTRACT complex logic into custom hooks
ALWAYS wrap components in error boundaries for production
ALWAYS handle async errors properly in async operations
ALWAYS provide user-friendly error messages in error handling
ALWAYS use virtualization for lists with 100+ items
ALWAYS implement proper key props for list items
ALWAYS lazy load heavy components using React.lazy for code splitting
ALWAYS use Suspense wrapper for lazy loaded components
USE local state for component-level state; LIFT state up when needed across multiple components; USE Context for avoiding prop drilling; USE Redux only for global state shared across multiple places
Wrap components receiving props withmemofor performance optimization
Files:
src/index.tsxsrc/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)
Ensure TypeScript types are explicit and proper; avoid use of
anytype
Files:
src/index.tsxsrc/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
src/state/slices/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
src/state/slices/**/*.ts: Migrations are required when changing persisted state structure (seesrc/state/migrations/)
Export selectors from slice using inlineselectorsproperty
Files:
src/state/slices/portfolioSlice/portfolioSlice.ts
src/state/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
src/state/**/*.{ts,tsx}: UsecreateDeepEqualOutputSelectorfrom@/state/selector-utilsfor deep equality checks
UsecreateCachedSelectorfromre-reselectfor parameterized selectors
Files:
src/state/slices/portfolioSlice/portfolioSlice.ts
{.env.development,.env.production}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
.env.developmentfor dev-only features and.env.productionfor prod settings
Files:
.env.production
src/config.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Default values always come from environment variables prefixed with
VITE_FEATURE_
Files:
src/config.ts
🧠 Learnings (25)
📚 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 src/config.ts : Default values always come from environment variables prefixed with `VITE_FEATURE_`
Applied to files:
.envsrc/vite-env.d.tsheaders/csps/hypelab.ts.env.productionsrc/config.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: To add a new feature flag: (1) Add to `FeatureFlags` type in `src/state/slices/preferencesSlice/preferencesSlice.ts`, (2) Add environment variable validation in `src/config.ts`, (3) Add to initial state in `preferencesSlice.ts`, (4) Add to test mock in `src/test/mocks/store.ts`, (5) Set appropriate values in `.env`, `.env.development`, and `.env.production`
Applied to files:
.env.env.production
📚 Learning: 2025-12-03T23:19:39.158Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11275
File: headers/csps/chains/plasma.ts:1-10
Timestamp: 2025-12-03T23:19:39.158Z
Learning: For CSP files in headers/csps/chains/, gomesalexandre prefers using Vite's loadEnv() pattern directly to load environment variables (e.g., VITE_PLASMA_NODE_URL, VITE_MONAD_NODE_URL) for consistency with existing second-class chain CSP files, rather than using getConfig() from src/config.ts, even though other parts of the codebase use validated config values.
Applied to files:
.envsrc/vite-env.d.tsheaders/csps/hypelab.ts.env.productionheaders/csps/index.tssrc/config.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:
src/vite-env.d.tssrc/config.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:
src/index.tsxheaders/csps/index.ts
📚 Learning: 2025-11-24T21:20:30.085Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/naming-conventions.mdc:0-0
Timestamp: 2025-11-24T21:20:30.085Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use descriptive import names and avoid renaming imports unless necessary
Applied to files:
src/index.tsx
📚 Learning: 2025-08-05T22:41:35.473Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10187
File: src/pages/Assets/Asset.tsx:1-1
Timestamp: 2025-08-05T22:41:35.473Z
Learning: In the shapeshift/web codebase, component imports use direct file paths like '@/components/ComponentName/ComponentName' rather than barrel exports. The AssetAccountDetails component should be imported as '@/components/AssetAccountDetails/AssetAccountDetails', not from a directory index.
Applied to files:
src/index.tsx
📚 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} : Use Chakra UI components and conventions
Applied to files:
src/index.tsx
📚 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:
src/index.tsx
📚 Learning: 2025-11-24T21:20:30.085Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/naming-conventions.mdc:0-0
Timestamp: 2025-11-24T21:20:30.085Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use named exports for components, functions, and utilities instead of default exports
Applied to files:
src/index.tsx
📚 Learning: 2025-10-01T07:42:40.195Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10596
File: src/components/Layout/Header/NavBar/WalletConnectedMenu.tsx:77-99
Timestamp: 2025-10-01T07:42:40.195Z
Learning: In WalletConnectedMenu.tsx's handleReconnectWallet handler, gomesalexandre prefers throwing an error for unsupported wallet types in the default case rather than gracefully handling with a fallback. His reasoning: "if we have a problem here, we have bigger problems" - only supported wallets (KeepKey, Ledger, MetaMask, Coinbase, Phantom) should reach the reconnect flow when disconnected/locked, so encountering an unsupported type indicates a larger architectural issue that should be surfaced explicitly rather than masked with graceful degradation.
Applied to files:
src/state/slices/portfolioSlice/portfolioSlice.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 src/state/slices/**/*.ts : Migrations are required when changing persisted state structure (see `src/state/migrations/`)
Applied to files:
src/state/slices/portfolioSlice/portfolioSlice.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:
src/state/slices/portfolioSlice/portfolioSlice.ts
📚 Learning: 2025-09-22T14:28:23.109Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10566
File: src/hooks/useLedgerConnectionState.ts:71-95
Timestamp: 2025-09-22T14:28:23.109Z
Learning: gomesalexandre designed useLedgerConnectionState to distinguish between USB device connection state and wallet pairing state. When pairing fails but USB is connected, connectionState should remain 'idle' to allow retries, while 'failed' is reserved for when the USB device is physically disconnected.
Applied to files:
src/state/slices/portfolioSlice/portfolioSlice.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: Each wallet has unique `walletId` (e.g., `metamask:0x123`, `ledger:ABC`)
Applied to files:
src/state/slices/portfolioSlice/portfolioSlice.ts
📚 Learning: 2025-08-22T13:03:36.919Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/Explore/Explore.tsx:110-113
Timestamp: 2025-08-22T13:03:36.919Z
Learning: In src/Routes/RoutesCommon.tsx, the /fox-ecosystem route is already properly gated using disable: !getConfig().VITE_FEATURE_RFOX_FOX_ECOSYSTEM_PAGE, which prevents direct navigation when the VITE_FEATURE_RFOX_FOX_ECOSYSTEM_PAGE flag is false.
Applied to files:
headers/csps/hypelab.ts
📚 Learning: 2025-09-16T13:17:02.938Z
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.
Applied to files:
.env.production
📚 Learning: 2025-12-09T21:07:22.474Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11335
File: packages/swapper/src/swappers/CetusSwapper/utils/helpers.ts:3-3
Timestamp: 2025-12-09T21:07:22.474Z
Learning: In packages/swapper/src/swappers/CetusSwapper, mysten/sui types (SuiClient, Transaction) must be imported from the nested path within cetusprotocol/aggregator-sdk (e.g., 'cetusprotocol/aggregator-sdk/node_modules/mysten/sui/client') because the aggregator SDK bundles its own version of mysten/sui. Direct imports from 'mysten/sui' break at runtime even when specified in package.json.
Applied to files:
headers/csps/index.ts
📚 Learning: 2025-08-07T11:20:44.614Z
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.
Applied to files:
src/config.ts
📚 Learning: 2025-08-08T11:40:55.734Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx:41-41
Timestamp: 2025-08-08T11:40:55.734Z
Learning: In MultiHopTrade confirm flow (src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx and related hooks), there is only one active trade per flow. Because of this, persistent (module/Redux) dedupe for QuotesReceived in useTrackTradeQuotes is not necessary; the existing ref-based dedupe is acceptable.
Applied to files:
src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-07-29T15:04:28.083Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10139
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandableStepperSteps.tsx:109-115
Timestamp: 2025-07-29T15:04:28.083Z
Learning: In src/components/MultiHopTrade/components/TradeConfirm/components/ExpandableStepperSteps.tsx, the component is used under an umbrella that 100% of the time contains the quote, making the type assertion `activeTradeQuote?.steps[currentHopIndex] as TradeQuoteStep` safe. Adding conditional returns before hooks would violate React's Rules of Hooks.
Applied to files:
src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-08-08T11:41:36.971Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:88-109
Timestamp: 2025-08-08T11:41:36.971Z
Learning: In MultiHopTrade Confirm flow (src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx), the Confirm route does not remount; navigating away goes to the swapper input page. Therefore, persistent deduplication across remounts for quote tracking is unnecessary; a ref-based single-mount dedupe is sufficient.
Applied to files:
src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 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/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-11-24T21:20:17.804Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-11-24T21:20:17.804Z
Learning: Applies to **/*.{tsx,jsx} : ALWAYS use `useErrorToast` hook for displaying errors with translated error messages and handle different error types appropriately
Applied to files:
src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-10-07T03:44:27.350Z
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10760
File: src/components/ManageHiddenAssets/ManageHiddenAssetsList.tsx:78-84
Timestamp: 2025-10-07T03:44:27.350Z
Learning: In the ShapeShift web codebase, the following are stable references and do not need to be included in useCallback/useMemo dependency arrays:
- `navigate` from `useBrowserRouter()` hook
- Modal control objects (like `walletDrawer`) from `useModal()` hook (including their `isOpen`, `close`, and `open` methods)
- These are backed by stable context providers
Applied to files:
src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
🧬 Code graph analysis (3)
src/state/slices/portfolioSlice/portfolioSlice.ts (2)
src/lib/mixpanel/mixPanelSingleton.ts (1)
getMixPanel(9-41)src/lib/hypelab/hypelabSingleton.ts (1)
trackHypeLabEvent(18-23)
headers/csps/hypelab.ts (1)
headers/types.ts (1)
Csp(2-2)
src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx (1)
src/lib/hypelab/hypelabSingleton.ts (1)
trackHypeLabEvent(18-23)
🪛 dotenv-linter (4.0.0)
.env
[warning] 274-274: [UnorderedKey] The VITE_ENABLE_HYPELAB key should go before the VITE_HYPELAB_PROPERTY_SLUG key
(UnorderedKey)
.env.production
[warning] 3-3: [UnorderedKey] The VITE_ENABLE_HYPELAB key should go before the VITE_FEATURE_MIXPANEL key
(UnorderedKey)
[warning] 4-4: [UnorderedKey] The VITE_FEATURE_ADDRESS_BOOK key should go before the VITE_FEATURE_MIXPANEL key
(UnorderedKey)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Call / Static
🔇 Additional comments (3)
headers/csps/hypelab.ts (1)
1-15: LGTM!The CSP configuration correctly uses the
loadEnvpattern (consistent with other CSP files), checks the appropriate feature flag, and points to the correct HypeLab domain for both script and connection sources.src/lib/hypelab/hypelabSingleton.ts (2)
18-23: LGTM!The function properly handles the optional nature of HypeLab analytics by silently failing when unavailable. The use of the
HypeLabEventenum provides good type safety.
1-5: The enum is well-implemented with descriptive naming and proper string values. However, verification that these event names align with HypeLab's expected event schema requires access to HypeLab's SDK documentation, which is not available in this repository. The integration relies on the external HypeLab Analytics API at https://api.hypelab.com, so confirming the event names match their expected schema would require consulting HypeLab's documentation directly.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.env (1)
272-274: Reorder the HypeLab environment variables to match dotenv-linter expectations.The static analysis tool flags an unordered key issue:
VITE_ENABLE_HYPELABshould precedeVITE_HYPELAB_PROPERTY_SLUGin the file.Apply this diff to correct the order:
-# HypeLab -VITE_HYPELAB_PROPERTY_SLUG=4793fe16ca VITE_ENABLE_HYPELAB=false +VITE_HYPELAB_PROPERTY_SLUG=4793fe16ca
📜 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.
📒 Files selected for processing (1)
.env(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 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 src/config.ts : Default values always come from environment variables prefixed with `VITE_FEATURE_`
Applied to files:
.env
📚 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: To add a new feature flag: (1) Add to `FeatureFlags` type in `src/state/slices/preferencesSlice/preferencesSlice.ts`, (2) Add environment variable validation in `src/config.ts`, (3) Add to initial state in `preferencesSlice.ts`, (4) Add to test mock in `src/test/mocks/store.ts`, (5) Set appropriate values in `.env`, `.env.development`, and `.env.production`
Applied to files:
.env
📚 Learning: 2025-12-03T23:19:39.158Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11275
File: headers/csps/chains/plasma.ts:1-10
Timestamp: 2025-12-03T23:19:39.158Z
Learning: For CSP files in headers/csps/chains/, gomesalexandre prefers using Vite's loadEnv() pattern directly to load environment variables (e.g., VITE_PLASMA_NODE_URL, VITE_MONAD_NODE_URL) for consistency with existing second-class chain CSP files, rather than using getConfig() from src/config.ts, even though other parts of the codebase use validated config values.
Applied to files:
.env
🪛 dotenv-linter (4.0.0)
.env
[warning] 274-274: [UnorderedKey] The VITE_ENABLE_HYPELAB key should go before the VITE_HYPELAB_PROPERTY_SLUG key
(UnorderedKey)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Install and Cache

Description
Replaces Addressable Pixel with HypeLabs Pixel as per marketing request
Sister PR in website-frontend: shapeshift/website-frontend#87
Issue (if applicable)
closes #11181
Risk
Low risk, marketing tracking change so unlikely to break anything in the app
Testing
Engineering
Operations
Screenshots (if applicable)
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.