### Run Next.js Development Server Source: https://github.com/rainbow-me/rainbow/blob/develop/src/design-system/docs/README.md Commands to start the local development server for a Next.js application. Ensure you have Node.js and npm or yarn installed. This command will build and serve the application on http://localhost:3000. ```bash npm run dev # or yarn dev ``` -------------------------------- ### Run Example App for React Native Animated Charts Source: https://github.com/rainbow-me/rainbow/blob/develop/src/react-native-animated-charts/README.md Instructions to clone the repository, install dependencies, and run the example application for React Native Animated Charts on Android and iOS. ```bash yarn && cd ios && pod install && cd .. react-native run-android react-native run-ios ``` -------------------------------- ### Build and Run Android App on Linux Source: https://github.com/rainbow-me/rainbow/blob/develop/README.md Builds, installs, and starts the debug version of the Android application in an emulator using React Native CLI. ```shell yarn android ``` -------------------------------- ### Start React Native Webserver Source: https://github.com/rainbow-me/rainbow/blob/develop/README.md Starts the React Native development server, which is necessary for both macOS and Linux development. ```shell yarn start ``` -------------------------------- ### Install System Dependencies on Linux Source: https://github.com/rainbow-me/rainbow/blob/develop/README.md Installs essential system packages for development on Linux, including libsecret-tools and Watchman. ```shell sudo apt install libsecret-tools watchman ``` -------------------------------- ### Install Project Bundles and Pods on macOS Source: https://github.com/rainbow-me/rainbow/blob/develop/README.md Installs project-specific bundles and CocoaPods dependencies. This step is crucial after setting up CocoaPods. ```shell yarn install-bundle && yarn install-pods ``` -------------------------------- ### Install Xcode Command Line Tools Source: https://github.com/rainbow-me/rainbow/blob/develop/ios/fastlane/README.md Ensures the latest version of Xcode command line tools are installed, which is a prerequisite for installing and using fastlane. ```bash xcode-select --install ``` -------------------------------- ### Install Fastlane using Gem Source: https://github.com/rainbow-me/rainbow/blob/develop/ios/fastlane/README.md Installs the fastlane tool using the RubyGems package manager. The '-NV' flags ensure verbose output and version checking during installation. ```bash [sudo] gem install fastlane -NV ``` -------------------------------- ### Extend Portal for Custom Explainer Sheets Source: https://github.com/rainbow-me/rainbow/blob/develop/src/screens/Portal/README.md Shows an example of extending the Portal primitive to create specialized explainer sheets, such as the `@/screens/Explain` sheet. This extension re-exports `useOpen` and `open` and provides pre-built components (`Emoji`, `Title`, `Body`) for consistent explainer sheet design. The example demonstrates opening an explainer sheet with custom content and configuration. ```tsx import * as explain from '@/screens/Explain'; explain.open( () => ( <> 💰 This is a title And this is body text ), { sheetHeight: 640 } ); ``` -------------------------------- ### Install Watchman on macOS Source: https://github.com/rainbow-me/rainbow/blob/develop/README.md Installs Watchman, a file watching service, using Homebrew. This is a dependency for macOS development. ```shell brew install watchman ``` -------------------------------- ### Maestro Retry Command Configuration Source: https://github.com/rainbow-me/rainbow/blob/develop/e2e/README.md A YAML example showing how to configure Maestro to retry specific commands to mitigate flakiness in E2E tests. This configuration specifies the maximum number of retries. ```yaml - retry: maxRetries: 3 commands: # ... flaky commands ``` -------------------------------- ### iOS Accessibility Identifier Troubleshooting Example Source: https://github.com/rainbow-me/rainbow/blob/develop/e2e/README.md Illustrates a common issue on iOS where `testID` is not recognized due to parent view accessibility. The example shows the incorrect and corrected way to apply `testID` for accessibility. ```tsx import React from 'react'; import { View } from 'react-native'; // Incorrect usage: // Correct usage: ``` -------------------------------- ### Install react-native-animated-charts Source: https://github.com/rainbow-me/rainbow/blob/develop/src/react-native-animated-charts/README.md Installs the react-native-animated-charts package using yarn. Requires prior installation of react-native-reanimated. ```bash yarn add react-native-animated-charts ``` -------------------------------- ### Consume New GraphQL Client in React (TypeScript/React) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/graphql/README.md This example shows how to consume a newly created GraphQL client in a React component using TypeScript. It imports the `exampleClient` and uses it to call the `getUsers` query. This represents the final step in integrating a new GraphQL API client. ```tsx import { exampleClient } from '@/graphql'; function fetchUsers() { return exampleClient.getUsers(); } ``` -------------------------------- ### Install Fastlane using Homebrew Source: https://github.com/rainbow-me/rainbow/blob/develop/ios/fastlane/README.md An alternative method to install fastlane using the Homebrew package manager for macOS. ```bash brew install fastlane ``` -------------------------------- ### Setup and Identify User for Analytics Source: https://context7.com/rainbow-me/rainbow/llms.txt Initializes the analytics system by setting a device ID and identifying the user with associated properties like wallet type, app version, and platform. It uses dynamic import for utility functions. ```typescript import { analytics } from '@/analytics'; // Initialize analytics with device ID async function setupAnalytics() { const { getOrCreateDeviceId } = await import('@/analytics/utils'); const deviceId = await getOrCreateDeviceId(); analytics.setDeviceId(deviceId); // Identify user with properties analytics.identify({ walletType: 'mnemonic', appVersion: '2.0.15', platform: 'ios' }); } ``` -------------------------------- ### Install CocoaPods on macOS Source: https://github.com/rainbow-me/rainbow/blob/develop/README.md Installs CocoaPods, a dependency manager for Swift and Objective-C, using RubyGems. This is required for iOS development. ```shell sudo gem install cocoapods ``` -------------------------------- ### Run iOS E2E Tests with Maestro Source: https://github.com/rainbow-me/rainbow/blob/develop/e2e/README.md Locally run E2E tests on iOS. Requires setting an environment variable, building the app in release mode, and executing the test script. Specific flows can be targeted using a flag. ```shell yarn ios --mode Release ./scripts/e2e-run.sh --flow ./e2e/flows/auth/ImportWallet.yaml ``` -------------------------------- ### Create New GraphQL Client Instance (TypeScript) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/graphql/README.md This TypeScript code demonstrates how to create a new GraphQL client instance in `index.ts`. It imports the configuration, a utility for fetch requesters, and the generated SDK for the new 'example' client. This makes the new client available for consumption throughout the application. ```tsx import { config } from './config'; import { getFetchRequester } from './utils/getFetchRequester'; import { getSdk as getEnsSdk } from './__generated__/ens'; import { getSdk as getMetadataSdk } from './__generated__/metadata'; + import { getSdk as getExampleSdk } from './__generated__/example'; export const ensClient = getEnsSdk(getFetchRequester(config.ens.schema.url)); export const metadataClient = getMetadataSdk( getFetchRequester(config.metadata.schema.url) ); + export const exampleClient = getEnsSdk(getFetchRequester(config.example.schema.url)); ``` -------------------------------- ### Device Storage Operations in TypeScript Source: https://github.com/rainbow-me/rainbow/blob/develop/src/storage/README.md Demonstrates basic CRUD operations (set, get, remove, removeMany) on the device-scoped local storage using the `@/storage` module. This store is scoped to the device level. ```typescript import * as storage from '@/storage'; storage.device.set(['doNotTrack'], true); storage.device.get(['doNotTrack']); storage.device.remove(['doNotTrack']); storage.device.removeMany([], ['doNotTrack']); ``` -------------------------------- ### Configure New GraphQL Client (JavaScript) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/graphql/README.md This JavaScript snippet shows how to add a new entry to the `config.js` file to configure a new GraphQL client. It includes the schema URL and the document path for the new 'example' client. This step is crucial for the code generator to recognize and process the new GraphQL endpoint. ```javascript exports.config = { ens: { schema: { url: 'https://api.thegraph.com/subgraphs/name/ensdomains/ens', method: 'POST' }, document: './queries/ens.graphql', }, metadata: { schema: { url: 'https://metadata.p.rainbow.me/v1/graph', method: 'GET' }, document: './queries/metadata.graphql', }, + example: { + schema: { url: 'https://example.com/graphql' }, + document: './queries/example.graphql', + }, }; ``` -------------------------------- ### Run Android E2E Tests with Maestro Source: https://github.com/rainbow-me/rainbow/blob/develop/e2e/README.md Locally run E2E tests on Android. Similar to iOS, this involves setting an environment variable, building the app in release mode, and using the test script. It supports running specific test flows. ```shell yarn android --mode Release ./scripts/e2e-run.sh --flow ./e2e/flows/auth/ImportWallet.yaml ``` -------------------------------- ### Simplify Data Example Source: https://github.com/rainbow-me/rainbow/blob/develop/src/react-native-animated-charts/README.md Shows how to use the simplifyData helper function to reduce the density of data points. It selects one point per 'pickRange' and can optionally include the first and last points using the 'includeExtremes' flag. ```javascript import { simplifyData } from 'react-native-animated-charts'; const simplified = simplifyData(data, 10, true); ``` -------------------------------- ### Keychain Basic Operations (TypeScript) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/keychain/README.md Demonstrates basic operations like setting, checking existence, getting, setting objects, retrieving shared web credentials, checking supported biometry, removing, and clearing the keychain. ```typescript import * as keychain from '@/keychain'; await keychain.set('my-keychain-key', 'value', await keychain.getPrivateAccessControlOptions()); const bool = await keychain.has('my-keychain-key'); const result = await keychain.get('my-keychain-key'); await keychain.setObject('my-object', { foo: 'bar' }); const result = await keychain.getObject('my-object'); await keychain.setSharedWebCredentials('username', 'password'); const result = await keychain.getSharedWebCredentials('username', 'password'); const biometryType = await keychain.getSupportedBiometryType(); await keychain.remove('my-keychain-key'); await keychain.remove('my-object'); await keychain.clear(); ``` -------------------------------- ### E2E Test Command Deep Link Structure Source: https://github.com/rainbow-me/rainbow/blob/develop/e2e/README.md A YAML snippet demonstrating the structure for deep links used to trigger E2E test commands within the application. These commands are handled by `TestDeeplinkHandler.tsx` and can accept parameters. ```yaml - openLink: rainbow://e2e/?param1=value1¶m2=value2 ``` -------------------------------- ### Basic Chart Example using ChartPathProvider, ChartPath, ChartDot Source: https://github.com/rainbow-me/rainbow/blob/develop/src/react-native-animated-charts/README.md Demonstrates a basic animated chart implementation using ChartPathProvider, ChartPath, and ChartDot components. It uses monotone cubic interpolation for data smoothing and renders a chart with a yellow stroke and blue dots on a black background. ```jsx import React from 'react'; import { Dimensions, View } from 'react-native'; import { ChartDot, ChartPath, ChartPathProvider, monotoneCubicInterpolation } from 'react-native-animated-charts'; export const { width: SIZE } = Dimensions.get('window'); export const data = [ { x: 1453075200, y: 1.47 }, { x: 1453161600, y: 1.37 }, { x: 1453248000, y: 1.53 }, { x: 1453334400, y: 1.54 }, { x: 1453420800, y: 1.52 }, { x: 1453507200, y: 2.03 }, { x: 1453593600, y: 2.1 }, { x: 1453680000, y: 2.5 }, { x: 1453766400, y: 2.3 }, { x: 1453852800, y: 2.42 }, { x: 1453939200, y: 2.55 }, { x: 1454025600, y: 2.41 }, { x: 1454112000, y: 2.43 }, { x: 1454198400, y: 2.2 }, ]; const points = monotoneCubicInterpolation(data)(40); const BasicExample = () => ( ); ``` -------------------------------- ### Submit iOS Beta Build to TestFlight using Fastlane Source: https://github.com/rainbow-me/rainbow/blob/develop/ios/fastlane/README.md Executes the fastlane command to submit a new beta build of an iOS application to Apple TestFlight. This is a core action for beta distribution. ```bash fastlane ios beta ``` -------------------------------- ### Consume GraphQL Query in React (TypeScript/React) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/graphql/README.md This example shows how to consume a newly added GraphQL query within a React component using TypeScript. It imports the generated client (`ensClient`) and uses it to call the `getDomain` query, passing the required `id` argument. This illustrates the final step of integrating new GraphQL functionality. ```tsx import { ensClient } from '@/graphql'; function fetchDomain(id: string) { return ensClient.getDomain({ id }); } ``` -------------------------------- ### Initialize and Track Analytics Events (TypeScript) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/analytics/README.md Demonstrates the initialization of the analytics wrapper and tracking of various events like user identification, application mount, state changes, and screen views. It shows how to pass user properties, event names, and screen-specific metadata. ```typescript import { analytics } from '@/analytics'; analytics.identify({ ...userProperties, }); analytics.track(analytics.event.applicationDidMount); analytics.track(analytics.event.appStateChange, { category: 'app state', label: 'foo', }); analytics.screen(Routes.SWAPS_PROMO_SHEET, { ...metadata, }); ``` -------------------------------- ### Scoped MMKV Storage for Device and Network/Wallet Data Source: https://context7.com/rainbow-me/rainbow/llms.txt This snippet showcases the use of a strongly-typed MMKV storage system for managing application data. It includes examples for device-scoped settings, persisting across re-installs via keychain, and network/wallet-scoped storage for managing data like contact lists, with specific examples for setting, getting, and removing data based on network and wallet identifiers. ```typescript import * as storage from '@/storage'; // Device-scoped storage (persists across app reinstalls via keychain) function configureDeviceSettings() { // Enable/disable analytics tracking storage.device.set(['doNotTrack'], true); // Get tracking preference const doNotTrack = storage.device.get(['doNotTrack']); // Returns: boolean // Remove setting storage.device.remove(['doNotTrack']); } // Network and wallet scoped storage import { Storage } from '@/storage'; type ContactSchema = { contacts: Array<{ name: string; address: string; }>; }; enum Network { Mainnet = 'mainnet', Optimism = 'optimism', Polygon = 'polygon' } const networkWalletStorage = new Storage<[Network, string], ContactSchema>({ id: 'networkAndWallet' }); // Store contacts for specific network and wallet networkWalletStorage.set( [Network.Mainnet, '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', 'contacts'], [ { name: 'rainbow.eth', address: '0x7a1...' }, { name: 'vitalik.eth', address: '0xd8d...' } ] ); // Retrieve contacts - returns typed array const contacts = networkWalletStorage.get([ Network.Mainnet, '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', 'contacts' ]); // Type: Array<{ name: string; address: string; }> // Remove specific keys networkWalletStorage.removeMany( [Network.Mainnet, '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'], ['contacts'] ); ``` -------------------------------- ### Scoped Storage with Network and Wallet in TypeScript Source: https://github.com/rainbow-me/rainbow/blob/develop/src/storage/README.md Illustrates how to create and use a storage instance scoped to both network and wallet addresses. It shows setting and retrieving data, emphasizing the requirement for both scope identifiers to be provided. ```typescript type NetworkAndWalletSchema = { contacts: Contact[]; }; enum Network { Mainnet = 'mainnet', Optimism = 'optimism', } type WalletAddress = `Ox${string}`; const networkAndWallet = new Storage<[Network, WalletAddress], NetworkAndWalletSchema>({ id: 'networkAndWallet', }); networkAndWallet.set([Network.Mainnet, '0x12345', 'contacts'], [{ name: 'rainbow.eth', address: '0x67890' }]); const contacts: Contact[] = networkAndWallet.get([Network.Mainnet, '0x12345', 'contacts']); ``` -------------------------------- ### Initialize Wallet Notification Settings Source: https://github.com/rainbow-me/rainbow/blob/develop/src/notifications/settings/__tests__/initialization.test.txt Tests the initial state preparation for wallet notification settings. It verifies that new settings are correctly identified and that already saved settings are mapped appropriately. Dependencies include storage mechanisms and helper functions like _prepareInitializationState and createInitialSettingsForNewlyAddedAddresses. ```javascript notificationSettingsStorage.set( WALLET_TOPICS_STORAGE_KEY, JSON.stringify(stateBefore) ); const initState = _prepareInitializationState(); expect(initState).toEqual({ newSettings: stateBefore, subscriptionQueue: [], alreadySaved: new Map([ [ TEST_ADDRESS_1, { index: 0, settings: stateBefore[0], }, ], [ TEST_ADDRESS_2, { index: 1, settings: stateBefore[1], }, ], ]), }); const queue = createInitialSettingsForNewlyAddedAddresses( [ { address: TEST_ADDRESS_1, // changed to be owned from watched wallet relationship: WalletNotificationRelationship.OWNER, }, { address: TEST_ADDRESS_2, relationship: WalletNotificationRelationship.WATCHER, }, ], initState ); // changed the current type to "owned", also wallet now is not initialized since it needs to re-subscribe const changedState = { type: WalletNotificationRelationship.OWNER, successfullyFinishedInitialSubscription: false, }; expect(queue).toEqual([ { ...stateBefore[0], ...changedState, }, ]); const stateAfter = JSON.parse( notificationSettingsStorage.getString(WALLET_TOPICS_STORAGE_KEY) ?? '[]' ); // unchanged because the work will happen when queue i processed expect(stateAfter).toEqual([ { ...stateBefore[0], ...changedState, }, stateBefore[1], ]); }); }); describe('subscription queue processing implementation happy path', () => { test('running a subscription queue with no items in it causes zero effects', async () => { notificationSettingsStorage.set( WALLET_TOPICS_STORAGE_KEY, JSON.stringify([ { address: TEST_ADDRESS_1, type: WalletNotificationRelationship.OWNER, successfullyFinishedInitialSubscription: false, topics: DEFAULT_ENABLED_TOPIC_SETTINGS, enabled: false, }, ]) ); expect( JSON.parse( notificationSettingsStorage.getString(WALLET_TOPICS_STORAGE_KEY) ?? '[]' ) ).toEqual([ { address: TEST_ADDRESS_1, type: WalletNotificationRelationship.OWNER, successfullyFinishedInitialSubscription: false, topics: DEFAULT_ENABLED_TOPIC_SETTINGS, enabled: false, }, ]); }); test('running subscription queue processing for items that were not yet properly subscribed with firebase should subscribe them properly', async () => { notificationSettingsStorage.set( WALLET_TOPICS_STORAGE_KEY, JSON.stringify([ { address: TEST_ADDRESS_1, type: WalletNotificationRelationship.OWNER, successfullyFinishedInitialSubscription: false, topics: DEFAULT_ENABLED_TOPIC_SETTINGS, enabled: false, }, ]) ); const stateAfter = { address: TEST_ADDRESS_1, type: WalletNotificationRelationship.OWNER, successfullyFinishedInitialSubscription: true, topics: DEFAULT_ENABLED_TOPIC_SETTINGS, enabled: true, }; expect( JSON.parse( notificationSettingsStorage.getString(WALLET_TOPICS_STORAGE_KEY) ?? '[]' ) ).toEqual([stateAfter]); }); test('running subscription queue processing for wallets that were imported after being watched should unsubscribe them completely and resubscribe them properly again', async () => { const stateBefore = { address: TEST_ADDRESS_1, type: WalletNotificationRelationship.OWNER, successfullyFinishedInitialSubscription: false, topics: DEFAULT_ENABLED_TOPIC_SETTINGS, enabled: false, }; notificationSettingsStorage.set( WALLET_TOPICS_STORAGE_KEY, JSON.stringify([stateBefore]) ); const stateAfter = { ...stateBefore, successfullyFinishedInitialSubscription: true, enabled: true, }; expect( JSON.parse( notificationSettingsStorage.getString(WALLET_TOPICS_STORAGE_KEY) ?? '[]' ) ).toEqual([stateAfter]); }); }); describe('subscription queue processing implementation error path', () => { ``` -------------------------------- ### Install ens-avatar using npm or yarn Source: https://github.com/rainbow-me/rainbow/blob/develop/src/ens-avatar/README.md Installs the ens-avatar library for use in your project. This is the first step to integrating avatar resolution capabilities. ```bash # npm npm i @ensdomains/ens-avatar # yarn yarn add @ensdomains/ens-avatar ``` -------------------------------- ### Monotone Cubic Interpolation Example Source: https://github.com/rainbow-me/rainbow/blob/develop/src/react-native-animated-charts/README.md Illustrates the usage of monotoneCubicInterpolation for creating a smooth curve that preserves monotonicity. This method is inspired by d3-shape and ensures no spurious oscillations. ```javascript import { monotoneCubicInterpolation as interpolator } from 'react-native-animated-charts'; const interpolatedData = interpolator({ data, range: 80 }); ``` -------------------------------- ### Run GraphQL Code Generation (Shell) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/graphql/README.md This command is used to run the GraphQL code generation tool. After defining new queries or mutations in `.graphql` files, this command must be executed to generate the necessary TypeScript types and fetcher functions. It assumes the user is in the root directory of the 'rainbow' repository. ```shell > yarn graphql-codegen ``` -------------------------------- ### BSpline Interpolation Example Source: https://github.com/rainbow-me/rainbow/blob/develop/src/react-native-animated-charts/README.md Demonstrates how to use bSplineInterpolation to generate equidistant points from a dataset. It accepts an object with 'data', 'range', 'includeExtremes', and 'removePointsSurroundingExtremes' parameters. The 'degree' parameter defaults to 3. ```javascript import { bSplineInterpolation as interpolator } from 'react-native-animated-charts'; const interpolatedData = interpolator({ data, range: 80 }); ``` -------------------------------- ### Create a Navigable Portal Route Wrapper Source: https://github.com/rainbow-me/rainbow/blob/develop/src/screens/Portal/README.md Provides a template for creating a custom navigable route for a Portal. It demonstrates using the `Portal` sheet wrapper, which utilizes `SimpleSheet`, to structure the content of a route. This approach is useful for creating deep-linkable portal screens by assigning a separate route name and configuring navigation. ```tsx export function Portal() { const { params } = useRoute>(); return ( ... ); } ``` -------------------------------- ### Run NFT Store Pagination Tests (Bash) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/state/nfts/README.md This command executes the unit tests for the NFT store's pagination functionality. It targets a specific test file within the project, ensuring that the pagination logic, including stale page handling and error recovery, functions as expected. ```bash npm test src/state/nfts/__tests__/createNftsStore.test.ts ``` -------------------------------- ### Open a Portal Sheet with React Hook Source: https://github.com/rainbow-me/rainbow/blob/develop/src/screens/Portal/README.md Demonstrates how to use the `useOpen` hook from the Portal primitive to open a new sheet within a React component. It shows the basic structure of providing a JSX element for the sheet content and optional configuration options like `sheetHeight`. Dependencies include the `portal` module and React components like `Box`, `Text`, and `Button`. ```tsx import * as portal from '@/screens/Portal'; export function Comp() { const { open } = portal.useOpen(); const handlePress = () => { open( () => ( <> Hello world ), { sheetHeight: 400 } ); }; return ; } ``` -------------------------------- ### Initialize Default Notification Group Settings Source: https://github.com/rainbow-me/rainbow/blob/develop/src/notifications/settings/__tests__/initialization.test.txt Adds default notification group settings ('owner' and 'watcher') to storage if they do not already exist. This function ensures that basic group configurations are available when the application starts or when settings are reset. It relies on `notificationSettingsStorage` for persistent storage. ```typescript import { addDefaultNotificationGroupSettings, notificationSettingsStorage, WALLET_GROUPS_STORAGE_KEY, } from '@/notifications/settings'; describe('groups initialization', function () { test('adding default group settings if they do not exist in MMKV', () => { notificationSettingsStorage.delete(WALLET_GROUPS_STORAGE_KEY); const before = notificationSettingsStorage.getString( WALLET_GROUPS_STORAGE_KEY ); expect(before).toBeUndefined(); addDefaultNotificationGroupSettings(); const after = notificationSettingsStorage.getString( WALLET_GROUPS_STORAGE_KEY ); expect(after).toEqual('{"owner":true,"watcher":false}'); }); }); ``` -------------------------------- ### Future Scoped Storage Wrapper in TypeScript Source: https://github.com/rainbow-me/rainbow/blob/develop/src/storage/README.md Presents a design for a future `NetworkAndWalletStorage` class that simplifies scoped storage operations by internally managing network and wallet context, allowing key-only access. ```typescript import { Storage } from '@/storage' class NetworkAndWalletStorage { walletAddress?: WalletAddress network?: Network storage: Storage<[Network, WalletAddress], Schema> constructor() { this.storage = new Storage<[Network, WalletAddress], Schema>({ id: 'networkAndWallet' }) } setWalletAddress(walletAddress: string) { this.walletAddress = walletAddress } setNetwork(network: string) { this.network = network } set(key: Key, data: Schema[Key]): void { if (!this.network || !this.walletAddress) { throw new Error(`ScopedStorage requires both network and walletAddress`) } this.storage.set([this.network, this.walletAddress, key], data) } // ...etc... } export networkAndWallet = new NetworkAndWalletStorage() ``` ```typescript import { networkAndWallet } from '@/storage/networkAndWallet'; networkAndWallet.set('contacts', [{ name: 'rainbow.eth', address: '0x67890' }]); ``` -------------------------------- ### Configure Web3 Providers (TypeScript) Source: https://context7.com/rainbow-me/rainbow/llms.txt Manages multi-chain RPC provider configuration with caching mechanisms. It allows fetching providers, utilizing cached instances, and configuring custom RPC endpoints. The code demonstrates cross-chain balance checks using these providers. ```typescript import { getProvider, getCachedProviderForNetwork, proxyCustomRpcEndpoint } from '@/handlers/web3'; import { ChainId } from '@/state/backendNetworks/types'; // Get or create provider with caching function getChainProvider(chainId: ChainId) { // Check cache first let provider = getCachedProviderForNetwork(chainId); if (!provider) { // Create new provider (automatically cached) provider = getProvider({ chainId }); } return provider; } // Use custom RPC endpoint function useCustomRPC() { const customEndpoint = 'https://my-custom-node.com'; const proxiedUrl = proxyCustomRpcEndpoint(ChainId.mainnet, customEndpoint); console.log('Proxied RPC:', proxiedUrl); // Output: https://rpc-proxy.rainbow.me/1/API_KEY?custom_rpc=https%3A%2F%2Fmy-custom-node.com } // Multi-chain operations async function crossChainBalanceCheck(address: string) { const chains = [ChainId.mainnet, ChainId.polygon, ChainId.optimism, ChainId.arbitrum]; const balances = await Promise.all( chains.map(async (chainId) => { const provider = getProvider({ chainId }); const balance = await provider.getBalance(address); return { chainId, balance: balance.toString() }; }) ); return balances; } ``` -------------------------------- ### Perform Wallet Health Checks (TypeScript) Source: https://context7.com/rainbow-me/rainbow/llms.txt Automates wallet backup status and keychain integrity checks upon application start. It includes functions to run various checks and manage the display of backup prompts to the user. State management for backups is handled via `backupsStore`. ```typescript import { runWalletBackupStatusChecks, runKeychainIntegrityChecks, runFeatureUnlockChecks } from '@/handlers/walletReadyEvents'; async function performWalletHealthChecks() { // Check keychain integrity on app start await runKeychainIntegrityChecks(); // Check if wallet needs backup const needsBackup = await runWalletBackupStatusChecks(); if (needsBackup) { console.log('Wallet backup prompt shown to user'); // User will see backup sheet modal } // Run feature unlock checks (rewards, campaigns) const featureUnlocked = await runFeatureUnlockChecks(); if (featureUnlocked) { console.log('Feature unlock sheet displayed'); } } // Backup state management import { backupsStore } from '@/state/backups/backups'; function checkBackupStatus() { const { status, backupProvider, lastBackupPromptAt, timesPromptedForBackup } = backupsStore.getState(); console.log('Backup status:', status); // 'ready', 'loading', 'error' console.log('Provider:', backupProvider); // 'cloud', 'manual', null console.log('Last prompted:', new Date(lastBackupPromptAt)); console.log('Times prompted:', timesPromptedForBackup); } ``` -------------------------------- ### Initialize Notification Settings: Existing Subscriptions Source: https://github.com/rainbow-me/rainbow/blob/develop/src/notifications/settings/__tests__/initialization.test.txt Tests the initialization process when notification settings are already stored and successfully initialized for all wallets. It verifies that the system correctly identifies existing settings and does not create unnecessary subscription queues. ```typescript test('running initialization when it was already successfully initialized before and no work needs to be done', () => { const stateBefore = [ { address: TEST_ADDRESS_1, type: WalletNotificationRelationship.OWNER, successfullyFinishedInitialSubscription: true, topics: DEFAULT_ENABLED_TOPIC_SETTINGS, enabled: true, }, { address: TEST_ADDRESS_2, topics: DEFAULT_ENABLED_TOPIC_SETTINGS, type: WalletNotificationRelationship.WATCHER, successfullyFinishedInitialSubscription: true, enabled: false, }, ]; notificationSettingsStorage.set( WALLET_TOPICS_STORAGE_KEY, JSON.stringify(stateBefore) ); const initState = _prepareInitializationState(); expect(initState).toEqual({ newSettings: stateBefore, subscriptionQueue: [], alreadySaved: new Map([ [ TEST_ADDRESS_1, { index: 0, settings: stateBefore[0], }, ], [ TEST_ADDRESS_2, { index: 1, settings: stateBefore[1], }, ], ]), }); const queue = createInitialSettingsForNewlyAddedAddresses( [ { address: TEST_ADDRESS_1, relationship: WalletNotificationRelationship.OWNER, }, { address: TEST_ADDRESS_2, relationship: WalletNotificationRelationship.WATCHER, }, ], initState ); expect(queue).toEqual([]); const stateAfter = JSON.parse( notificationSettingsStorage.getString(WALLET_TOPICS_STORAGE_KEY) ?? '[]' ); expect(stateAfter).toEqual(stateBefore); }); ``` -------------------------------- ### Create, Import, and Watch Wallets with BIP39 and Keychain Source: https://context7.com/rainbow-me/rainbow/llms.txt This snippet demonstrates wallet management functions including creating a new wallet with a mnemonic seed phrase, importing an existing wallet using a seed phrase, and setting up a read-only watch address. It utilizes the 'bip39' library for mnemonic generation and a secure 'keychain' for storing sensitive data like seed phrases and addresses, ensuring user privacy and security. ```typescript import { generateMnemonic } from 'bip39'; import { deriveAccountFromMnemonic } from '@/utils/wallet'; import * as keychain from '@/keychain'; import walletTypes from '@/helpers/walletTypes'; // Generate new wallet with seed phrase async function createNewWallet(): Promise<{ address: string; mnemonic: string }> { // Generate 12-word mnemonic const mnemonic = generateMnemonic(); // Derive first account (index 0) from mnemonic const wallet = await deriveAccountFromMnemonic(mnemonic, 0); // Store seed phrase in secure keychain const accessControl = await keychain.getPrivateAccessControlOptions(); await keychain.set('seedPhrase_wallet_1', mnemonic, accessControl); // Store wallet address await keychain.set('address_wallet_1', wallet.address, accessControl); return { address: wallet.address, mnemonic: mnemonic }; } // Import existing wallet from seed phrase async function importWalletFromSeed(mnemonic: string): Promise { const { isValidMnemonic } = await import('@/handlers/web3'); if (!isValidMnemonic(mnemonic)) { throw new Error('Invalid mnemonic seed phrase'); } const wallet = await deriveAccountFromMnemonic(mnemonic, 0); // Store in keychain with biometric protection const accessControl = await keychain.getPrivateAccessControlOptions(); await keychain.set('imported_seedPhrase', mnemonic, accessControl); await keychain.set('imported_address', wallet.address, accessControl); return wallet.address; } // Create read-only wallet (watch address) async function createWatchWallet(ethereumAddress: string): Promise { const { isValidAddress } = await import('ethereumjs-util'); if (!isValidAddress(ethereumAddress)) { throw new Error('Invalid Ethereum address'); } // Store as read-only wallet await keychain.setObject('watch_wallet', { address: ethereumAddress, type: walletTypes.readOnly, imported: true }); } ``` -------------------------------- ### Update Analytics Event Key (TypeScript) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/analytics/README.md Provides an example of how to update the key of an existing analytics event without changing its production value. This is useful for aligning event keys with evolving naming conventions or better categorizing events. It emphasizes that the event value (the actual event name) should remain immutable once in production. ```typescript export const event = { // value stays the same financeSwapsFormUserSubmitted: 'swaps.user_form.submitted', }; ``` -------------------------------- ### Basic Logger Interface Source: https://github.com/rainbow-me/rainbow/blob/develop/src/logger/README.md Presents the core interface for the logger, outlining the available methods and their general parameter structure. This provides a quick reference for common logging operations. ```typescript import { logger } from '@/logger' logger.debug(message[, metadata, debugContext]) logger.info(message[, metadata]) logger.log(message[, metadata]) logger.warn(message[, metadata]) logger.error(error[, metadata]) ``` -------------------------------- ### Secure Wallet Operations with Keychain Source: https://context7.com/rainbow-me/rainbow/llms.txt Handles secure storage and retrieval of sensitive data using the keychain, supporting biometric authentication and discriminated union error handling. It allows setting, getting, checking existence, and removing key-value pairs, as well as storing and retrieving objects. Dependencies include the '@keychain' module. Outputs include retrieved data, boolean values for existence checks, and biometry types. ```typescript import * as keychain from '@/keychain'; async function secureWalletOperations() { // Store sensitive data with biometric protection const accessControl = await keychain.getPrivateAccessControlOptions(); await keychain.set('private_key_wallet_1', '0xabc123...', accessControl); // Check if key exists const hasPrivateKey = await keychain.has('private_key_wallet_1'); // Returns: boolean // Retrieve with error handling const result = await keychain.get('private_key_wallet_1'); if (result.value) { // Safe to use - biometric auth succeeded const privateKey = result.value; console.log('Retrieved private key:', privateKey); } else { // Handle specific error types switch(result.error) { case keychain.ErrorType.UserCanceled: console.log('User canceled biometric authentication'); break; case keychain.ErrorType.NotAuthenticated: console.log('Biometric authentication failed'); break; case keychain.ErrorType.Unavailable: console.log('Keychain unavailable on device'); break; default: console.log('Unknown keychain error:', result.error); } } // Store and retrieve objects await keychain.setObject('wallet_metadata', { name: 'My Primary Wallet', color: 0, backedUp: true, type: 'mnemonic' }); const metadataResult = await keychain.getObject('wallet_metadata'); if (metadataResult.value) { console.log('Wallet name:', metadataResult.value.name); } // Check supported biometry const biometryType = await keychain.getSupportedBiometryType(); console.log('Biometry:', biometryType); // 'FaceID', 'TouchID', 'Fingerprint', etc. // Remove specific key await keychain.remove('private_key_wallet_1'); // Clear all keychain data (use with caution!) // await keychain.clear(); } ``` -------------------------------- ### Run Android Production Release Action Source: https://github.com/rainbow-me/rainbow/blob/develop/android/fastlane/README.md Initiates the 'production' action for Android, deploying the application to the Google Play Store's production track for all users. This is the final step in releasing an application update. The command can be executed using fastlane directly or through bundler. ```sh [bundle exec] fastlane android production ``` -------------------------------- ### Blockchain Provider and Transaction Operations Source: https://context7.com/rainbow-me/rainbow/llms.txt Facilitates interactions with blockchain networks by providing methods to get blockchain providers (single and batched) for specific chains and perform various transaction operations. It supports fetching block numbers, account balances, transaction counts, estimating gas, and interacting with ERC-20 tokens. Dependencies include modules from '@handlers/web3', '@ethersproject/contracts', and '@ethersproject/units'. Outputs include various blockchain data like block numbers, balances, and transaction details. ```typescript import { getProvider, getBatchedProvider } from '@/handlers/web3'; import { ChainId } from '@/state/backendNetworks/types'; import { Contract } from '@ethersproject/contracts'; import { parseEther } from '@ethersproject/units'; // Get blockchain provider for specific chain async function blockchainOperations() { // Get provider for Ethereum mainnet const provider = getProvider({ chainId: ChainId.mainnet }); // Get current block number const blockNumber = await provider.getBlockNumber(); console.log('Current block:', blockNumber); // Get account balance const balance = await provider.getBalance('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'); console.log('Balance (Wei):', balance.toString()); // Get transaction count (nonce) const nonce = await provider.getTransactionCount('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'); // Estimate gas for transaction const gasEstimate = await provider.estimateGas({ to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', value: parseEther('0.1') }); // Get batched provider for multiple requests const batchProvider = getBatchedProvider({ chainId: ChainId.polygon }); // ERC-20 token contract interaction const ERC20_ABI = [ 'function balanceOf(address owner) view returns (uint256)', 'function transfer(address to, uint amount) returns (bool)', 'function decimals() view returns (uint8)', 'function symbol() view returns (string)' ]; const tokenAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'; // USDC const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider); // Get token balance const tokenBalance = await tokenContract.balanceOf('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'); const decimals = await tokenContract.decimals(); const symbol = await tokenContract.symbol(); console.log(`Balance: ${tokenBalance.toString()} ${symbol} (${decimals} decimals)`); // Check if chain is Layer 2 const { isL2Chain } = await import('@/handlers/web3'); const isL2 = isL2Chain({ chainId: ChainId.optimism }); // Returns: true return { blockNumber, balance, nonce, gasEstimate, tokenBalance }; } ``` -------------------------------- ### Add GraphQL Query to Existing Client (GraphQL) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/graphql/README.md This snippet demonstrates how to add a new GraphQL query to an existing `.graphql` file. It uses a diff format to show the addition of the `getDomain` query. This is the first step in extending an existing GraphQL client's capabilities. ```graphql // src/graphql/queries/ens.graphql query getRegistration($id: ID!) { registration(id: $id) { id registrationDate expiryDate registrant { id } } } +query getDomain($id: ID!) { + domain(id: $id) { + id + name + } +} ``` -------------------------------- ### Initialize Notification Settings: Imported Wallet Subscription Source: https://github.com/rainbow-me/rainbow/blob/develop/src/notifications/settings/__tests__/initialization.test.txt Tests the initialization flow when a watched wallet was imported using a seed phrase or private key. It verifies how the system handles the subscription status for such wallets, assuming they were previously initialized successfully. ```typescript test('running initialization when it was already initialized before, but one of the watched wallets was imported with seed phrase or private key', () => { const stateBefore = [ { address: TEST_ADDRESS_1, // before the wallet is a watched one type: WalletNotificationRelationship.WATCHER, // it was properly initialized before successfullyFinishedInitialSubscription: true, topics: DEFAULT_ENABLED_TOPIC_SETTINGS, ``` -------------------------------- ### Run Android Beta Release Action Source: https://github.com/rainbow-me/rainbow/blob/develop/android/fastlane/README.md Performs the 'beta' action for Android, distributing the application to the beta testing track on the Google Play Store. This is used for testing with a larger group of external testers before a full production release. The command can be run with or without 'bundle exec'. ```sh [bundle exec] fastlane android beta ``` -------------------------------- ### Analytics Event Naming Convention (Bash) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/analytics/README.md Describes the recommended naming convention for analytics events, which follows a pattern of `.`. It explains how to structure descriptive names with multiple dot-separated parts, increasing specificity from left to right, and using past-tense for the action. ```bash . swaps.user_form.submitted swaps.backend_processing.network_failed ``` -------------------------------- ### Enable Design System Playground Source: https://github.com/rainbow-me/rainbow/blob/develop/src/design-system/README.md This code snippet enables the design system playground for local development. It requires adding a specific export to `src/config/debug.js`. When enabled, the application renders the playground instead of the regular app, allowing for isolated viewing of design system components. ```javascript export const designSystemPlaygroundEnabled = true; ``` -------------------------------- ### Add New GraphQL Query Definition (GraphQL) Source: https://github.com/rainbow-me/rainbow/blob/develop/src/graphql/README.md This snippet illustrates how to define a new GraphQL query in a new `.graphql` file. It shows the addition of a `getUsers` query. This is the initial step when introducing a new GraphQL query that doesn't belong to an existing schema definition. ```graphql // src/graphql/queries/example.graphql +query getUsers { + id + firstName + lastName +} ```