### 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 titleAnd 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
+}
```