` | Token metadata indexed by "chainId\_tokenAddress" keys |
# Examples
Source: https://docs.caldera.xyz/metalayer/sdk/examples
Step-by-step examples of using the Metalayer SDK
## Client Example
Basic implementation steps for building a cross-chain bridge using the Metalayer client directly.
### 1. Initialize Client
Set up the Metalayer client with your API key to access bridge functionality.
```typescript theme={null}
import { MetalayerClient, OrderStatus } from '@metalayer/sdk';
const client = MetalayerClient.init({
apiKey: process.env.METALAYER_API_KEY!,
environment: 'mainnet',
});
```
### 2. Get Supported Chains
Fetch available chains to determine valid bridge routes for your application.
```typescript theme={null}
const { chains } = await client.getSupportedChains();
console.log('Available chains:', chains);
```
### 3. Get Tokens
Retrieve token information for the chains you want to support in your bridge interface.
```typescript theme={null}
const { tokensByChain } = await client.getTokens();
const ethereumTokens = tokensByChain[1] || [];
```
### 4. Request Quote
Get bridge quotes based on user selections to show routing options and fees.
```typescript theme={null}
const quoteResponse = await client.quote({
sourceChainId: 1, // Ethereum Mainnet
sourceTokenAddress: '0x0000000000000000000000000000000000000000', // ETH
destinationChainId: 33139, // ApeChain
destinationTokenAddress: '0x0000000000000000000000000000000000000000', // ETH
amount: BigInt('1000000000000000000'), // 1 ETH
senderAddress: '0xYourWalletAddress',
});
const bestQuote = quoteResponse.quotes[0];
```
### 5. Execute Transaction
Execute the bridge transaction by processing each step in the quote with your wallet client.
```typescript theme={null}
for (const step of bestQuote.steps) {
switch (step.action.case) {
case 'transactionRequest':
const hash = await walletClient.sendTransaction({
to: step.action.value.to,
data: step.action.value.data,
value: step.action.value.value,
});
break;
case 'eip712Data':
await walletClient.signTypedData(step.action.value);
break;
}
}
```
### 6. Monitor Status
Track the bridge transaction progress to provide status updates to users.
```typescript theme={null}
const order = await client.getOrder({
sourceTransactionHash: '0xTxHash',
sourceChainId: 1,
});
if (order.status === OrderStatus.FULFILLED) {
console.log('Bridge completed successfully!');
} else if (order.status === OrderStatus.FAILED) {
console.log('Bridge failed');
} else if (order.status === OrderStatus.PENDING) {
console.log('Bridge in progress...');
}
```
## React Hook Example
Basic implementation steps for building a cross-chain bridge using Metalayer SDK hooks. For detailed hook configuration and provider setup, see [Hooks](/metalayer/sdk/hooks).
### 1. Get Supported Chains
Fetch the list of supported chains to populate source and destination chain selectors in your UI. This data enables users to choose which networks they want to bridge between.
```tsx theme={null}
import { useSupportedChains } from '@metalayer/sdk';
const { data: chainsData } = useSupportedChains();
const chains = chainsData?.chains || [];
```
### 2. Get Tokens
Retrieve available tokens organized by chain to build token selection lists. Use this data to create filtered token dropdowns that update based on the user's selected source and destination chains.
```tsx theme={null}
import { useTokens } from '@metalayer/sdk';
const { data: tokensData } = useTokens();
const tokens = tokensData?.tokensByChain || {};
```
### 3. Get Quote
Request bridge quotes based on user selections from your UI. This provides routing options, fees, and estimated completion times for the bridge transaction.
```tsx theme={null}
import { useQuote } from '@metalayer/sdk';
const { data: quoteData, isLoading } = useQuote({
sourceChainId: 1, // Ethereum Mainnet
sourceTokenAddress: '0x0000000000000000000000000000000000000000', // ETH
destinationChainId: 33139, // ApeChain
destinationTokenAddress: '0x0000000000000000000000000000000000000000', // ETH
amount: BigInt('1000000000000000000'), // 1 ETH
senderAddress: '0xYourWalletAddress',
});
const bestQuote = quoteData?.quotes[0];
```
### 4. Execute Transaction
Execute the bridge transaction using the selected quote. This typically involves multiple steps like token approvals followed by the actual bridge transaction, with each step requiring user wallet confirmation.
```typescript theme={null}
// Execute quote steps
for (const step of bestQuote.steps) {
switch (step.action.case) {
case 'transactionRequest':
await walletClient.sendTransaction({
to: step.action.value.to,
data: step.action.value.data,
value: step.action.value.value,
});
break;
case 'eip712Data':
await walletClient.signTypedData(step.action.value);
break;
}
}
```
### 5. Monitor Status
Track the bridge transaction progress to provide real-time status updates to users. Use this to display progress indicators, completion confirmations, or error states in your UI.
```tsx theme={null}
import { useOrderPolling, OrderStatus } from '@metalayer/sdk';
const { data: order } = useOrderPolling({
sourceTransactionHash: '0xTxHash',
sourceChainId: 1,
});
// Check order status - see OrderStatus Values section for all possible values
if (order?.status === OrderStatus.FULFILLED) {
console.log('Bridge completed successfully!');
} else if (order?.status === OrderStatus.FAILED) {
console.log('Bridge failed');
} else if (order?.status === OrderStatus.PENDING) {
console.log('Bridge in progress...');
}
```
# Getting Started
Source: https://docs.caldera.xyz/metalayer/sdk/getting-started
Get started with the Metalayer SDK for cross-chain interoperability
## Features
* Cross-chain quote aggregation
* Full TypeScript support
* React hooks integration
* Viem compatibility
**Looking for a pre-built UI?** If you want to execute bridge transactions with a ready-made interface, consider using the [Metalayer Widget](/metalayer/widget/getting-started) instead. The Widget uses this SDK under the hood and provides a production-ready UI with built-in theming, wallet integration, and automatic transaction handling.
## Installation
```bash pnpm theme={null}
pnpm add viem @metalayer/sdk
```
```bash npm theme={null}
npm install viem @metalayer/sdk
```
```bash yarn theme={null}
yarn add viem @metalayer/sdk
```
If you plan to use the SDK's React hooks, you'll need to install React Query as a peer dependency.
### Installing React Query
```bash pnpm theme={null}
pnpm add @tanstack/react-query
```
```bash npm theme={null}
npm install @tanstack/react-query
```
```bash yarn theme={null}
yarn add @tanstack/react-query
```
## API Key Setup
Contact our team to get your API key.
## Requirements
* Node.js 20+
* TypeScript 5.0+ (recommended)
* React 16+ (for hooks)
* Viem 2.0+ (peer dependency)
## Next Steps
For complete implementation examples and detailed bridge flows, see [Examples](/metalayer/sdk/examples).
# React Hooks
Source: https://docs.caldera.xyz/metalayer/sdk/hooks
React hooks for the Metalayer SDK
## Setup
```tsx theme={null}
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { MetalayerProvider, type MetalayerConfig } from '@metalayer/sdk';
const queryClient = new QueryClient();
const config: MetalayerConfig = {
apiKey: 'your-api-key',
environment: 'mainnet',
};
function App() {
return (
);
}
```
## Available Hooks
### `useSupportedChains()`
Get supported blockchain networks.
```tsx theme={null}
import { useSupportedChains } from '@metalayer/sdk';
const { data, isLoading, error } = useSupportedChains();
const chains = data?.chains;
```
### `useTokens(params?)`
Get token information by chain.
```tsx theme={null}
import { useTokens } from '@metalayer/sdk';
const { data, isLoading } = useTokens({
chainId: 1 // Optional: filter by chain
});
const tokensByChain = data?.tokensByChain;
```
### `useQuote(params, interval?)`
Get quotes for cross-chain bridging with real-time updates.
```tsx theme={null}
import { useQuote } from '@metalayer/sdk';
const {
quote, // Best quote based on preferences (default: 'bestReturn')
quotes, // Full list of quotes
isLoading,
error,
refetch
} = useQuote({
sourceChainId: 1,
sourceTokenAddress: '0x...',
destinationChainId: 33139,
destinationTokenAddress: '0x...',
amount: BigInt('1000000000000000000'),
senderAddress: '0x...',
});
```
### `useOrderPolling(params, interval?)`
Poll order status with automatic updates.
```tsx theme={null}
import { useOrderPolling } from '@metalayer/sdk';
const {
data: order,
isLoading,
error
} = useOrderPolling({
sourceTransactionHash: '0xTxHash',
sourceChainId: 1,
}, 15000); // Poll every 15 seconds
```
### `useWalletOrders(address)`
Get all orders for a specific wallet address.
```tsx theme={null}
import { useWalletOrders } from '@metalayer/sdk';
const {
data: orders,
isLoading,
error
} = useWalletOrders('0xWalletAddress');
```
### `useMetalayer()`
Access the Metalayer client instance for direct API calls.
```tsx theme={null}
import { useMetalayer } from '@metalayer/sdk';
function Component() {
const { router } = useMetalayer();
// Use router directly for client method calls
const handleQuote = async () => {
const quote = await router.quote({
sourceChainId: 1,
destinationChainId: 33139,
// ... other params
});
};
return Use router for direct API calls
;
}
```
# Utilities
Source: https://docs.caldera.xyz/metalayer/sdk/utilities
SDK utility functions for common operations
## Utility Functions
The SDK provides utility functions for common operations:
### `chainToViemChain(chain)`
Convert a Metalayer [Chain](/metalayer/sdk/api-reference#chain) object to Viem chain format. Use the result as your **wagmi `chains`** list and pass the same viem `Chain` values into **`@metalayer/widget`** helpers such as [`createWidgetTransport`](/metalayer/widget/components#createwidgettransport-chain), [`createWidgetClient`](/metalayer/widget/components#createwidgetclient-chain), and [`createWidgetTransportsRecord`](/metalayer/widget/components#createwidgettransportsrecord-chains) (see [Widget Components](/metalayer/widget/components#rpc-transport-helpers)).
```typescript theme={null}
import { chainToViemChain } from '@metalayer/sdk';
const viemChain = chainToViemChain(chain);
```
### `chainsToViemChains(chains)`
Convert an array of Metalayer [Chain](/metalayer/sdk/api-reference#chain) objects to an array of Viem chains. Invalid or non-EVM chains are filtered out. The returned array is suitable for wagmi and for the widget transport helpers linked above.
```typescript theme={null}
import { chainsToViemChains } from '@metalayer/sdk';
const viemChains = chainsToViemChains(chains);
```
### `collectChainHttpRpcUrls(chain)`
Collects unique **HTTP** RPC URLs from a viem `Chain` produced by **`chainToViemChain`**, in Metalayer order: URLs under **`rpcUrls.default`**, then alternate slots **`rpc-0`**, **`rpc-1`**, … (sorted by index), which map to **`alternativeRpcs`** from the Metalayer chain. Used internally by **`createWidgetTransport`** in `@metalayer/widget`; you can use it directly when building custom viem **`fallback()`** stacks or other transports.
```typescript theme={null}
import { collectChainHttpRpcUrls } from '@metalayer/sdk';
const urls = collectChainHttpRpcUrls(viemChain);
```
### `formatQuoteProvider(provider)`
Format a [QuoteProvider](/metalayer/sdk/api-reference#quoteprovider) enum value to a readable string.
```typescript theme={null}
import { formatQuoteProvider, QuoteProvider } from '@metalayer/sdk';
const name = formatQuoteProvider(QuoteProvider.ACROSS); // "Across"
```
# Bridge Aggregator
Source: https://docs.caldera.xyz/metalayer/solutions/bridge-aggregation
Unified cross-chain transfers with optimal routing across 50+ networks
Caldera's bridge aggregator provides a single interface for cross-chain transfers while intelligently routing through the best available bridge provider for each transaction. Instead of users navigating multiple bridge UIs with different security models and wait times, the bridge aggregator aggregates quotes and presents the optimal route.
## The Problem
Traditional cross-chain transfers require users to:
* **Choose between multiple bridges** with different trade-offs
* **Navigate separate interfaces** for each bridge provider
* **Understand complex security models** and settlement times
* **Manage wrapped tokens** and liquidity requirements
## Single Interface, Multiple Providers
Metalayer provides unified access to cross-chain transfers through:
* **[SDK](/metalayer/sdk/getting-started)**: Complete developer toolkit for custom applications
* **[Widget](/metalayer/widget/getting-started)**: Embeddable UI component for instant deployment
Behind this single interface, Metalayer aggregates quotes from [multiple bridge providers](/metalayer/resources/aggregated-bridges) across [50+ supported networks](/metalayer/resources/widget-supported-chains), selecting the optimal route for each transfer.
## Next Steps
Complete integration guide
Embed ready-made UI
# MetaToken: Omnichain Tokens
Source: https://docs.caldera.xyz/metalayer/solutions/omnichain-tokens
Universal token portability with the same address on every chain
Metatoken establishes a new standard for multichain tokens, allowing any asset to be universally portable across multiple chains with the same contract address on every network. Unlike traditional wrapped tokens that fragment liquidity, Metatoken maintains unified supply while enabling seamless cross-chain transfers.
## The Problem
Traditional tokens face critical limitations in a multichain world:
* **Asset Isolation**: Tokens trapped on their origin chains
* **Fragmented Liquidity**: Multiple wrapped versions across different networks
* **Complex Deployments**: Expensive and time-consuming multi-chain launches
* **Poor UX**: Users confused by different token addresses on each chain
* **Security Risks**: Third-party bridges controlling token movement
## How It Works
### Hub-Spoke Architecture
Metatoken uses a Hub-Spoke model with specialized contracts:
* **MetaERC20Hub**: Deployed on the token's home chain, locks/unlocks canonical tokens
* **MetaERC20Spoke**: Deployed on remote chains, mints/burns synthetic tokens
* **Security Threshold Routing**: High-value spoke-to-spoke transfers routed through hub for validation
### Transfer Flows
1. **Hub → Spoke**: Lock canonical tokens on hub, mint synthetic tokens on spoke
2. **Spoke → Hub**: Burn synthetic tokens on spoke, unlock canonical tokens on hub
3. **Spoke → Spoke (Low Value)**: Direct burn and mint between spokes
4. **Spoke → Spoke (High Value)**: Routed through hub with validator approval for security
This maintains unified supply across all networks with the same contract address everywhere.
## Key Benefits
* **Unified Supply**: Single global token supply, no wrapped token confusion
* **Capital Efficient**: No liquidity pools or slippage, always 1:1 exchange
* **Deterministic Addresses**: Same contract address on every chain
* **Security Controls**: Configurable thresholds and validator approval for high-value transfers
* **Emergency Recovery**: Admin functions for handling stuck transfers while maintaining conservation of funds
* **Cost-Effective**: Included with Caldera rollup deployments
## Deployment
MetaTokens are currently deployed and managed by Caldera. This ensures proper security configuration, validator setup, and integration with the Metalayer infrastructure.
Projects interested in deploying their token as a MetaToken should contact our team to discuss requirements, timeline, and integration process.
## Next Steps
Discuss omnichain token deployment
Review contract architecture
# Components & API
Source: https://docs.caldera.xyz/metalayer/widget/components
Complete API reference for the Metalayer Bridge Widget components
## WidgetProvider
The provider component that sets up the widget context and configuration.
### Props
| Prop | Type | Description | Default | Required |
| ----------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------- | ----------- | -------- |
| `sdkConfig` | **[MetalayerConfig](/metalayer/sdk/client-methods#metalayerconfig)** | SDK configuration | - | ✅ |
| `theme` | **[WidgetTheme](/metalayer/widget/theming#widgettheme)** | Theme configuration for customizing colors, corners, shadows, and more | `undefined` | ❌ |
| `defaultSource` | **[DefaultChainToken](#defaultchaintoken)** | Default source chain and token | `undefined` | ❌ |
| `defaultDestination` | **[DefaultChainToken](#defaultchaintoken)** | Default destination chain and token | `undefined` | ❌ |
| `enabledChains` | **[Chain](/metalayer/sdk/api-reference#chain)\[]** | Pre-loaded chains (bypasses fetching) | `undefined` | ❌ |
| `onSupportedChainsLoad` | `(chains: Chain[]) => void` | Callback when chains are loaded | `undefined` | ❌ |
| `onError` | `(error: Error) => void` | Error handling callback | `undefined` | ❌ |
| `debugEnabled` | `boolean` | Enable debug logging | `false` | ❌ |
### SDK Configuration
```tsx Basic Configuration theme={null}
```
```tsx With Custom Options theme={null}
```
The `defaultOptions` configuration is optional. When not specified, the widget will display all supported chains and use default quote preference.
### Default Source and Destination
```tsx theme={null}
```
### Chain Loading Callback
`onSupportedChainsLoad` receives Metalayer [Chain](/metalayer/sdk/api-reference#chain) values from the SDK. Convert them with **[chainsToViemChains](/metalayer/sdk/utilities#chainstoviem)** or **[chainToViemChain](/metalayer/sdk/utilities#chaintoviem)** before passing them to wagmi, viem, or the [RPC transport helpers](#rpc-transport-helpers) below.
```tsx theme={null}
import { chainsToViemChains } from '@metalayer/sdk';
import { WidgetProvider } from '@metalayer/widget';
{
const viemChains = chainsToViemChains(chains);
updateWalletConfig(viemChains);
}}
>
```
#### Wagmi client callback (recommended)
Use **[createWidgetClient](#createwidgetclient-chain)** so each chain’s public client uses Metalayer’s RPC ordering and fallbacks. Build a non-empty viem chain tuple from `chainsToViemChains(metalayerChains)` (or a filtered list). Below, `ViemChain` is viem’s `Chain` type under an alias so it is not confused with the Metalayer `Chain` from the SDK.
```tsx theme={null}
import { chainsToViemChains } from '@metalayer/sdk';
import { createWidgetClient } from '@metalayer/widget';
import type { Chain as ViemChain } from 'viem';
import { createConfig } from 'wagmi';
function createWagmiConfig(chains: [ViemChain, ...ViemChain[]]) {
return createConfig({
chains,
multiInjectedProviderDiscovery: false,
client({ chain }) {
return createWidgetClient(chain);
},
});
}
```
> **📋 Note**: The widget requires an external `WagmiProvider` — it does not create its own. Use `onSupportedChainsLoad` to update your wagmi config with the widget's supported chains.
### RPC transport helpers
These helpers take **viem [`Chain`](https://viem.sh/docs/glossary/types#chain)** objects—the same shape returned by **`chainToViemChain`** / **`chainsToViemChains`** in `@metalayer/sdk`. Internally, **`createWidgetTransport`** calls **`collectChainHttpRpcUrls`** (see [SDK utilities](/metalayer/sdk/utilities#collectchainhttprpcurls-chain)) and builds a viem **`fallback`** transport over those HTTP URLs: Metalayer **default RPC** first, then **`rpc-0`**, **`rpc-1`**, … slots that **`chainToViemChain`** fills from **`alternativeRpcs`**. If no URLs are present, it falls back to viem’s default **`http()`** behavior.
#### `createWidgetTransport(chain)`
Returns a viem **`Transport`** for a single chain. It reads every HTTP RPC URL from the chain via **[`collectChainHttpRpcUrls`](/metalayer/sdk/utilities#collectchainhttprpcurls-chain)** and wraps them in a viem **`fallback()`** transport, so requests automatically retry on the next endpoint when one is rate-limited or unavailable. If no URLs are present it returns a plain `http()` transport.
Most integrations should use **[`createWidgetClient`](#createwidgetclient-chain)** (wagmi `client` callback) or **[`createWidgetTransportsRecord`](#createwidgettransportsrecord-chains)** (wagmi `transports` map) instead of calling this directly. Use `createWidgetTransport` when you need the raw transport for a custom viem client or want to compose it with other transports:
```typescript theme={null}
import { createWidgetTransport } from '@metalayer/widget';
import { createClient } from 'viem';
const client = createClient({
chain: viemChain,
transport: createWidgetTransport(viemChain),
});
```
#### `createWidgetClient(chain)`
Convenience wrapper: creates a viem **`Client`** with `createWidgetTransport` already wired in. This is the recommended way to configure wagmi via the **`client`** callback (see [Wagmi client callback](#wagmi-client-callback-recommended) above).
```typescript theme={null}
import { createWidgetClient } from '@metalayer/widget';
const client = createWidgetClient(viemChain);
```
#### `createWidgetTransportsRecord(chains)`
Builds **`Record`** keyed by chain id. Useful with RainbowKit’s `getDefaultConfig` or any wagmi setup that takes a `transports` map instead of a `client` callback:
```typescript theme={null}
import { createWidgetTransportsRecord } from '@metalayer/widget';
import { getDefaultConfig } from '@rainbow-me/rainbowkit';
const config = getDefaultConfig({
appName: 'My App',
projectId: 'your-walletconnect-project-id',
chains: supportedChains as unknown as readonly [Chain, ...Chain[]],
transports: createWidgetTransportsRecord(supportedChains),
});
```
For custom transport stacks (for example viem **`fallback()`**), you can read ordered HTTP URLs from a viem chain with **[collectChainHttpRpcUrls](/metalayer/sdk/utilities#collectchainhttprpcurls-chain)** in `@metalayer/sdk`.
### Theme Configuration
The widget supports extensive theming options including predefined themes, custom colors, fonts, and advanced overrides.
See the **[Theming](/metalayer/widget/theming)** page for complete customization options and visual examples.
## Widget
The main UI component that renders the bridge interface.
### Props
See **[WidgetProps](#widgetprops)** for the complete props reference.
```tsx theme={null}
openWalletModal()}
onDisconnectClick={() => disconnect()}
solanaSigner={solanaSigner}
/>
```
## Type Definitions
### MetalayerConfig
SDK configuration object. See **[MetalayerConfig](/metalayer/sdk/client-methods#metalayerconfig)** in the SDK documentation for full details.
### WidgetProps
| Property | Type | Description | Default | Required |
| ------------------------ | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ----------- | -------- |
| `onConnectClick` | `() => void` | Callback when user clicks connect | - | ✅ |
| `onDisconnectClick` | `() => void` | Callback when user clicks disconnect. When provided, widget manages wallet connection internally | `undefined` | ❌ |
| `onTransactionSubmitted` | `(sourceChainId?: number, destChainId?: number, amount?: string) => void` | Callback when user submits a transaction | `undefined` | ❌ |
| `onTokenSelected` | `(direction: 'source' \| 'destination', chainId: number, tokenAddress: string) => void` | Callback when user selects a token | `undefined` | ❌ |
| `source` | `{ chainId: number; tokenAddress?: string }` | Controlled source chain and token | `undefined` | ❌ |
| `destination` | `{ chainId: number; tokenAddress?: string }` | Controlled destination chain and token | `undefined` | ❌ |
| `isConnecting` | `boolean` | Whether a wallet is connecting | `false` | ❌ |
| `solanaSigner` | **[WidgetSolanaSigner](#widgetsolanasigner)** | Solana wallet signer for Solana transactions | `undefined` | ❌ |
| `className` | `string` | CSS class name for custom styling | `undefined` | ❌ |
When `onDisconnectClick` is provided, the widget manages wallet connection state internally and displays wallet info in the settings tab. If your page already handles wallet connect/disconnect logic, you don't need to set this prop; the widget will work with your existing wallet connection management.
```tsx theme={null}
import type { WidgetProps } from '@metalayer/widget';
```
### WidgetSolanaSigner
Solana support is currently in beta and requires additional dependencies. See the [EVM + Solana installation](/metalayer/widget/getting-started#evm--solana-beta) for setup instructions.
| Property | Type | Description | Default | Required |
| ----------------- | ---------------------------------------------------- | ----------------------------------------------------- | ------- | -------- |
| `address` | `string` | Solana wallet address | - | ✅ |
| `isConnected` | `() => boolean` | Function that returns whether the wallet is connected | - | ✅ |
| `signTransaction` | `(transaction: Transaction) => Promise` | Function to sign a Solana transaction | - | ✅ |
```tsx theme={null}
const solanaSigner = {
address: wallet.publicKey.toString(),
isConnected: () => wallet.connected,
signTransaction: async (transaction) => await wallet.signTransaction(transaction),
};
```
### DefaultChainToken
```tsx theme={null}
interface DefaultChainToken {
chainId: number;
tokenAddress: string;
}
```
| Property | Type | Description | Default | Required |
| -------------- | -------- | ------------------------------- | ------- | -------- |
| `chainId` | `number` | Chain ID of the default network | - | ✅ |
| `tokenAddress` | `string` | Token contract address | - | ✅ |
## Utility Functions
* **RPC transport helpers** — [`createWidgetTransport`](#createwidgettransport-chain), [`createWidgetClient`](#createwidgetclient-chain), and [`createWidgetTransportsRecord`](#createwidgettransportsrecord-chains) (see [above](#rpc-transport-helpers)).
* **Chain conversion** (from `@metalayer/sdk`) feeds those helpers; see [SDK Utilities](/metalayer/sdk/utilities):
* **[chainsToViemChains](/metalayer/sdk/utilities#chainstoviem)** — batch convert; skips invalid / non-EVM chains
* **[chainToViemChain](/metalayer/sdk/utilities#chaintoviem)** — single Metalayer chain → viem `Chain`
* **[collectChainHttpRpcUrls](/metalayer/sdk/utilities#collectchainhttprpcurls-chain)** — ordered HTTP RPC URLs on a viem `Chain` (for custom transports)
## CSS Styling
The widget requires a CSS import for proper styling:
```tsx theme={null}
import '@metalayer/widget/styles.css';
```
## Error Handling
### Error Callback
Handle errors in the widget through the `onError` callback:
```tsx theme={null}
{
console.error('Widget error:', error);
// Handle error (show toast, log to service, etc.)
}}
>
```
# Examples
Source: https://docs.caldera.xyz/metalayer/widget/examples
Step-by-step examples of integrating the Metalayer Bridge Widget
## Dynamic.xyz Integration
Complete integration with Dynamic.xyz for multi-chain wallet support.
This example includes Solana wallet support, which is currently in beta and requires additional dependencies. See the [EVM + Solana installation](/metalayer/widget/getting-started#evm--solana-beta) for setup instructions.
```tsx theme={null}
import { EthereumWalletConnectors } from '@dynamic-labs/ethereum';
import { DynamicContextProvider, mergeNetworks, useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { SolanaWalletConnectors, isSolanaWallet } from '@dynamic-labs/solana';
import { DynamicWagmiConnector } from '@dynamic-labs/wagmi-connector';
import { chainToViemChain, ChainArchitecture } from '@metalayer/sdk';
import { createWidgetClient, WidgetProvider, Widget } from '@metalayer/widget';
import { useState, useMemo } from 'react';
import type { Chain as ViemChain } from 'viem/chains';
import { mainnet } from 'viem/chains';
import { createConfig, WagmiProvider } from 'wagmi';
function createWagmiConfig(chains: [ViemChain, ...ViemChain[]]) {
return createConfig({
chains,
multiInjectedProviderDiscovery: false,
client({ chain }) {
return createWidgetClient(chain);
},
});
}
function App() {
const [evmNetworks, setEvmNetworks] = useState([]);
const [viemChains, setViemChains] = useState([mainnet]);
const wagmiConfig = useMemo(
() => createWagmiConfig(viemChains as [ViemChain, ...ViemChain[]]),
[viemChains],
);
return (
mergeNetworks(evmNetworks, networks),
},
}}
>
{
const ethereumChains = chains.filter(
(chain) => chain.identifier?.architecture === ChainArchitecture.ETHEREUM,
);
const nextViem = ethereumChains.map((chain) => chainToViemChain(chain));
setViemChains(nextViem.length ? nextViem : [mainnet]);
setEvmNetworks(
ethereumChains.map((chain) =>
viemChainToEvmNetwork(chainToViemChain(chain), chain.imageUrl),
),
);
}}
onError={(error) => console.error('Widget error:', error)}
>
);
}
function WidgetWrapper() {
const { setShowAuthFlow, primaryWallet } = useDynamicContext();
const solanaSigner = useMemo(() => {
if (!primaryWallet || !isSolanaWallet(primaryWallet)) return undefined;
return {
address: primaryWallet.address,
isConnected: () => !!primaryWallet.address,
signTransaction: async (transaction) => {
const signer = await primaryWallet.getSigner();
return await signer.signTransaction(transaction);
},
};
}, [primaryWallet]);
return (
setShowAuthFlow(true)}
/>
);
}
// `ViemChain` is viem's Chain (imported above as `Chain as ViemChain`).
// Helper function to convert Viem chain to EVM network
function viemChainToEvmNetwork(viemChain, iconUrl) {
return {
chainId: viemChain.id,
name: viemChain.name,
networkId: viemChain.id,
nativeCurrency: viemChain.nativeCurrency,
rpcUrls: Object.values(viemChain.rpcUrls.default).flat(),
blockExplorerUrls: viemChain.blockExplorers?.default?.url ? [viemChain.blockExplorers.default.url] : [],
isTestnet: viemChain.testnet,
iconUrls: iconUrl ? [iconUrl] : [],
};
}
```
## RainbowKit Integration
```tsx theme={null}
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { RainbowKitProvider, getDefaultConfig, useConnectModal } from '@rainbow-me/rainbowkit';
import { chainsToViemChains } from '@metalayer/sdk';
import { createWidgetTransportsRecord, WidgetProvider, Widget } from '@metalayer/widget';
import { useMemo, useState } from 'react';
import type { Chain as ViemChain } from 'viem/chains';
import { mainnet } from 'wagmi/chains';
import { WagmiProvider } from 'wagmi';
const queryClient = new QueryClient();
function App() {
const [viemChains, setViemChains] = useState([mainnet]);
const wagmiConfig = useMemo(
() =>
getDefaultConfig({
appName: 'My App',
projectId: 'your-walletconnect-project-id',
chains: viemChains as [ViemChain, ...ViemChain[]],
transports: createWidgetTransportsRecord(viemChains),
}),
[viemChains],
);
return (
{
const next = chainsToViemChains(chains);
if (next.length) setViemChains(next);
}}
>
);
}
function BridgePage() {
const { openConnectModal } = useConnectModal();
return (
);
}
```
## Privy Integration
Complete integration with Privy for multi-chain wallet support with external wagmi configuration.
```tsx theme={null}
import { type Chain, ChainArchitecture, chainToViemChain } from '@metalayer/sdk';
import { createWidgetTransportsRecord, WidgetProvider } from '@metalayer/widget';
import { PrivyProvider } from '@privy-io/react-auth';
import { createConfig, WagmiProvider } from '@privy-io/wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useMemo, useState } from 'react';
import type { Chain as ViemChain } from 'viem/chains';
import { mainnet } from 'viem/chains';
const queryClient = new QueryClient();
function Providers({ children }: { children: React.ReactNode }) {
const [supportedChains, setSupportedChains] = useState([mainnet]);
const wagmiConfig = useMemo(
() =>
createConfig({
chains: supportedChains as [ViemChain, ...ViemChain[]],
transports: createWidgetTransportsRecord(supportedChains),
}),
[supportedChains],
);
return (
{
// Filter for EVM chains and convert to viem chains
const evmChains = chains
.filter(chain => chain.identifier?.architecture === ChainArchitecture.ETHEREUM)
.map(chain => chainToViemChain(chain));
setSupportedChains(evmChains);
}}
>
{children}
);
}
```
```tsx theme={null}
import { Widget } from '@metalayer/widget';
import { usePrivy } from '@privy-io/react-auth';
function BridgePage() {
const { login, authenticated } = usePrivy();
return (
{
if (!authenticated) login();
}}
/>
);
}
```
## Next.js Setup
### App Router
In your `layout.tsx`:
```tsx theme={null}
import '@metalayer/widget/styles.css';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
{children}
);
}
```
### Pages Router
In your `_app.tsx`:
```tsx theme={null}
import '@metalayer/widget/styles.css';
export default function App({ Component, pageProps }) {
return (
);
}
```
## Vite Setup
When using the widget with Vite, you'll need to configure Node.js polyfills:
**Install the plugin:**
```bash pnpm theme={null}
pnpm add -D vite-plugin-node-polyfills
```
```bash npm theme={null}
npm install --save-dev vite-plugin-node-polyfills
```
```bash yarn theme={null}
yarn add -D vite-plugin-node-polyfills
```
**Update your `vite.config.ts`:**
```tsx theme={null}
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { nodePolyfills } from 'vite-plugin-node-polyfills';
export default defineConfig({
plugins: [
react(),
// Add this plugin to your existing plugins array
nodePolyfills({
globals: {
Buffer: true,
global: true,
process: true,
},
}),
],
// ... your other config options
});
```
If you already have other plugins configured, simply add the `nodePolyfills` plugin to your existing `plugins` array.
## Advanced Configuration
Configure the widget with advanced options for production use.
```tsx theme={null}
import { chainsToViemChains } from '@metalayer/sdk';
import { WidgetProvider, Widget } from '@metalayer/widget';
function AdvancedBridgeApp() {
return (
{
const viemChains = chainsToViemChains(chains);
if (viemChains.length) {
/* Recreate wagmi with viemChains + createWidgetClient or createWidgetTransportsRecord (see Widget Components docs) */
}
}}
onError={(error) => {
// Send to error tracking service
console.error('Widget error:', error);
// trackError(error);
}}
debugEnabled={process.env.NODE_ENV === 'development'}
>
{
// Your wallet connection logic
openWalletModal();
}}
solanaSigner={getSolanaSigner()} // If supporting Solana
/>
);
}
```
## Analytics Integration
Track widget usage and user interactions:
```tsx theme={null}
import { WidgetProvider, Widget } from '@metalayer/widget';
function AnalyticsEnabledWidget() {
const trackEvent = (eventName, properties) => {
// Your analytics implementation
analytics.track(eventName, properties);
};
return (
{
trackEvent('widget_chains_loaded', {
chainCount: chains.length
});
}}
>
{
trackEvent('wallet_connect_initiated');
openWalletModal();
}}
onTransactionSubmitted={(
sourceChainId: number,
destChainId?: number,
amount?: string
) => {
trackEvent('bridge_transaction_submitted', {
sourceChainId,
destChainId,
amount
});
}}
/>
);
}
```
# Getting Started
Source: https://docs.caldera.xyz/metalayer/widget/getting-started
Get started with the Metalayer Bridge Widget for cross-chain token bridging
## Features
* Cross-chain token bridging
* Multi-wallet support (Ethereum + Solana)
* Responsive design
* Framework agnostic
* Type-safe with TypeScript
## Installation
### EVM Only
```bash pnpm theme={null}
pnpm add viem wagmi @tanstack/react-query @metalayer/sdk @metalayer/widget
```
```bash npm theme={null}
npm install viem wagmi @tanstack/react-query @metalayer/sdk @metalayer/widget
```
```bash yarn theme={null}
yarn add viem wagmi @tanstack/react-query @metalayer/sdk @metalayer/widget
```
### EVM + Solana (beta)
```bash pnpm theme={null}
pnpm add viem wagmi @tanstack/react-query @solana/web3.js @solana/spl-token @metalayer/sdk @metalayer/widget
```
```bash npm theme={null}
npm install viem wagmi @tanstack/react-query @solana/web3.js @solana/spl-token @metalayer/sdk @metalayer/widget
```
```bash yarn theme={null}
yarn add viem wagmi @tanstack/react-query @solana/web3.js @solana/spl-token @metalayer/sdk @metalayer/widget
```
**Solana support is currently in beta** and not available in mainnet environments. Contact our team to enable Solana bridging for testnet.
## API Key Setup
Contact our team to get your API key.
## Basic Usage
```tsx theme={null}
import '@metalayer/widget/styles.css';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { WidgetProvider, Widget } from '@metalayer/widget';
import { WagmiProvider, createConfig, http } from 'wagmi';
import { mainnet } from 'wagmi/chains';
const queryClient = new QueryClient();
const wagmiConfig = createConfig({
chains: [mainnet],
transports: { [mainnet.id]: http() },
});
function App() {
return (
{
// Update your wagmi config with the widget's supported chains
}}
>
openWalletModal()} />
);
}
```
> **Note:** The widget requires a `WagmiProvider` from your application. Use
> `onSupportedChainsLoad` to update your wagmi config with the chains the widget supports.
# Migration Guide
Source: https://docs.caldera.xyz/metalayer/widget/migration
Upgrade from @metalayer/widget v0.x to v1.x
This guide helps you upgrade from `@metalayer/widget` v0.x to v1.x, which introduces a cleaner API, improved naming conventions, and a powerful new theme system.
## Breaking Changes
### 1. External WagmiProvider Required (disableWagmi removed)
The widget no longer ships an internal `WagmiProvider`. The `disableWagmi` prop has been removed — you **must** provide your own `WagmiProvider` in your application.
If you were already using `disableWagmi={true}`, simply remove the prop:
```diff theme={null}
```
If you were relying on the widget's internal `WagmiProvider` (the old default), wrap your app with your own:
```diff theme={null}
+
{
+ // Update wagmi config with supported chains
+ }}
>
+
```
Use `onSupportedChainsLoad` to update your wagmi config with the chains the widget supports.
### 2. Widget Props Structure
The widget no longer uses a nested `config` object. Props are now passed directly to the component.
```tsx Before (v0.x) theme={null}
```
```tsx After (v1.x) theme={null}
```
### 3. Callback Naming Changes
All callbacks have been renamed for clarity and consistency with React conventions:
| Old Name (v0.x) | New Name (v1.x) | Description |
| --------------------- | ------------------------ | ----------------------------------- |
| `onOpenConnectModal` | `onConnectClick` | Handler when user clicks connect |
| `onDisconnectWallet` | `onDisconnectClick` | Handler when user clicks disconnect |
| `onSubmitTransaction` | `onTransactionSubmitted` | Fired after transaction submission |
| `onSelectToken` | `onTokenSelected` | Fired after token selection |
### 4. Theme System
The `brandColor` prop has been **removed** in favor of the new comprehensive theme system.
```tsx Before (v0.x) theme={null}
```
```tsx After (v1.x) theme={null}
```
**Note:** `brandColor` has been completely removed in v1.x. You must use the new `theme` prop. See the [New Theme System Features](#new-theme-system-features) section below for comprehensive theming options.
### 5. WidgetProvider Props Update
The `chains` prop has been renamed to `enabledChains` for clarity:
```tsx Before (v0.x) theme={null}
```
```tsx After (v1.x) theme={null}
```
### 6. RPC / wagmi transports (Metalayer RPC helpers)
v1.x expects you to own **`WagmiProvider`** and therefore your **transports**. Using plain viem **`http()`** (or other defaults that ignore Metalayer metadata) does **not** use Metalayer’s ordered RPCs or **`alternativeRpcs`** as viem **`fallback`** endpoints, which can lead to rate limits or mismatches with the chains the widget loads.
Prefer:
* **`createWidgetClient`** with wagmi **`createConfig`** using a **`client({ chain }) { return createWidgetClient(chain) }`** callback, typically **`multiInjectedProviderDiscovery: false`**, after converting `onSupportedChainsLoad` chains with **`chainsToViemChains`** / **`chainToViemChain`** (see [Components](/metalayer/widget/components#wagmi-client-callback)), or
* **`createWidgetTransportsRecord(viemChains)`** with **`createConfig({ chains, transports })`** or RainbowKit **`getDefaultConfig({ transports })`**.
```diff theme={null}
- transports: { [chain.id]: http() },
+ transports: createWidgetTransportsRecord(viemChains),
```
## Step-by-Step Migration
### Step 1: Update Package Version
```bash pnpm theme={null}
pnpm update @metalayer/widget@^1.0.0
```
```bash npm theme={null}
npm update @metalayer/widget@^1.0.0
```
```bash yarn theme={null}
yarn upgrade @metalayer/widget@^1.0.0
```
### Step 2: Update Widget Component Usage
Find all `` components and update the props:
```diff theme={null}
- disconnect(),
- onSubmitTransaction: (source, dest, amount) => {
- console.log('Transaction submitted', { source, dest, amount });
- },
- className: 'rounded-xl',
- }}
- />
+ disconnect()}
+ onTransactionSubmitted={(source, dest, amount) => {
+ console.log('Transaction submitted', { source, dest, amount });
+ }}
+ className="rounded-xl"
+ />
```
### Step 3: Update WidgetProvider Theme
Replace `brandColor` with the new theme configuration:
```diff theme={null}
```
### Step 4: Update Token Selection Callbacks
If you're using token selection callbacks, update the naming:
```diff theme={null}
{
- console.log('Token selected', { direction, chainId, tokenAddress });
- }
- }}
+ onTokenSelected={(direction, chainId, tokenAddress) => {
+ console.log('Token selected', { direction, chainId, tokenAddress });
+ }}
/>
```
### Step 5: Update Controlled Token Selection
If using controlled source/destination props:
```diff theme={null}
```
## New Theme System Features
Take advantage of the new theming capabilities:
### Predefined Themes
```tsx theme={null}
```
### Custom Color Palette
```tsx theme={null}
```
### Feature Toggles
```tsx theme={null}
```
### Advanced Overrides
```tsx theme={null}
```
## Common Integration Updates
### RainbowKit
```diff theme={null}
function BridgePage() {
const { openConnectModal } = useConnectModal();
const { disconnect } = useDisconnect();
return (
);
}
```
### Dynamic.xyz
```diff theme={null}
function BridgePage() {
const { setShowAuthFlow } = useDynamicContext();
return (
setShowAuthFlow(true),
- }}
+ onConnectClick={() => setShowAuthFlow(true)}
/>
);
}
```
### ConnectKit
```diff theme={null}
function BridgePage() {
const { openConnectModal } = useModal();
const { disconnect } = useDisconnect();
return (
);
}
```
## TypeScript Updates
The type definitions have changed significantly:
```typescript theme={null}
// Old types (v0.x)
import type { WidgetProps, WidgetConfig } from '@metalayer/widget';
// v0.x used nested config object
const props: WidgetProps = {
config: {
onOpenConnectModal: () => void,
onDisconnectWallet?: () => void,
onSubmitTransaction?: (sourceChainId?: number, destChainId?: number, amount?: string) => void,
onSelectToken?: (direction: 'source' | 'destination', chainId: number, tokenAddress: string) => void,
className?: string,
source?: { chainId: number; tokenAddress?: string },
destination?: { chainId: number; tokenAddress?: string },
}
};
// New types (v1.x)
import type { WidgetProps } from '@metalayer/widget';
const props: WidgetProps = {
// REQUIRED callback
onConnectClick: () => void,
// Optional callbacks
onDisconnectClick?: () => void,
onTransactionSubmitted?: (
sourceChainId?: number,
destChainId?: number,
amount?: string
) => void,
onTokenSelected?: (
direction: 'source' | 'destination',
chainId: number,
tokenAddress: string
) => void,
// Optional configuration
source?: { chainId: number; tokenAddress?: string },
destination?: { chainId: number; tokenAddress?: string },
className?: string,
isConnecting?: boolean,
};
```
### Additional Exported Types
v1.x exports comprehensive TypeScript types for all configuration:
```typescript theme={null}
import type {
// Widget types
WidgetProps,
// Provider types
WidgetProviderProps,
// Theme types
ThemeConfig,
Theme,
ThemeMode,
PredefinedTheme,
ThemeFeatures,
CornerRadiusStyle,
ShadowStyle,
FontFamilyConfig,
GoogleFontsConfig,
CustomFontConfig,
// Solana types (if using Solana support)
WidgetSolanaSigner,
WidgetSolanaProps,
} from '@metalayer/widget';
```
## Troubleshooting
Remove the `config` wrapper and pass props directly to ``.
Use `theme={{ colors: { primary: 'your-color' } }}` instead.
Rename to `onConnectClick`.
Rename to `onTokenSelected`.
## Best Practices
1. **Use the new theme system** - It provides better customization and consistency
2. **Leverage TypeScript** - The new types provide better autocomplete and type safety
3. **Optional disconnect** - Only provide `onDisconnectClick` if your wallet library supports it
4. **Test callbacks** - Ensure all renamed callbacks are working correctly after migration
# Theming
Source: https://docs.caldera.xyz/metalayer/widget/theming
Customize the appearance of the Metalayer Bridge Widget
## Overview
The Metalayer Bridge Widget offers extensive theming capabilities to match your application's design. You can use predefined themes for quick setup or customize every aspect of the widget's appearance.
### Widget Properties
| Property | Type | Description |
| ------------ | -------------------------------------------------------- | ------------------------------- |
| `predefined` | `'comfy' \| 'modern'` | Use a predefined theme |
| `mode` | `'light' \| 'dark'` | Color mode |
| `colors` | **[ThemeColors](#available-palettes)** | Custom color palette |
| `corners` | `'none' \| 'minimal' \| 'soft' \| 'medium' \| 'rounded'` | Border radius style |
| `shadow` | `'none' \| 'sharp' \| 'light' \| 'heavy'` | Shadow style |
| `features` | **[ThemeFeatures](#widget-features)** | Feature toggles |
| `fontFamily` | **[FontFamily](#fontfamily)** | Font family configuration |
| `fonts` | **[FontsConfig](#fontsconfig)** | Font loading configuration |
| `overrides` | `Partial<`**[Theme](#theme-object-structure)**`>` | Direct theme property overrides |
## Color Palette
Using a single Hex color, the widget will generate a color palette for the widget.
```tsx theme={null}
```
### Available Palettes
The color palette properties that can be used to customize the widget.
| Property | Type | Description |
| --------- | -------- | -------------------------------------- |
| `primary` | `string` | Primary brand color (hex format) |
| `neutral` | `string` | Neutral/gray color (hex format) |
| `success` | `string` | Success state color (hex format) |
| `warning` | `string` | Warning state color (hex format) |
| `info` | `string` | Info state color (hex format) |
| `failure` | `string` | Error/failure state color (hex format) |
## Predefined Themes
The widget includes two predefined themes that provide a complete, cohesive look out of the box.
### Comfy Theme
The default theme with a warm, approachable aesthetic.
```tsx theme={null}
```
### Modern Theme
A sleek, contemporary design with sharper edges and a more minimal feel.
```tsx theme={null}
```
### Dark Mode
Enable dark mode on any theme by setting the `mode` property:
```tsx theme={null}
```
## Font Customization
The widget uses three font roles: **label** (headings/labels), **body** (body text), and **data** (numeric/monospace). Default fonts are Inter and Martian Mono.
#### Google Fonts
Specify font names for auto-loading from Google Fonts:
```tsx theme={null}
```
#### Recommended Fonts by Role
| Role | Recommended Google Fonts |
| ------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `label` | Inter, Montserrat, Fredoka, Oswald, Manrope, Merriweather, Noto Serif Display, Roboto, Jua, Bitcount |
| `body` | Inter, Montserrat, Manrope, Merriweather, Noto Serif Display, Roboto, Fredoka, Fira Code, Roboto Mono, Kode Mono, Martian Mono |
| `data` | Fira Code, Roboto Mono, Kode Mono, Martian Mono, Roboto, Inter, Montserrat, Manrope |
#### Google Fonts with Custom Weights
```tsx theme={null}
```
#### Custom Weight Choices
For more control over which font weights are used for regular and bold text, pass an object instead of a string:
```tsx theme={null}
```
**Default weights by role:**
| Role | `base` | `bold` |
| ----- | ------ | ------ |
| label | 700 | - |
| body | 400 | - |
| data | 500 | 700 |
The `bold` weight is currently only supported for the `data` role. Setting `bold` on `label` or `body` will show a dev warning and be ignored.
#### Custom Fonts
For fonts not on Google Fonts, use `customFonts` with woff2 URLs:
```tsx theme={null}
```
For multiple weights:
```tsx theme={null}
fonts: {
customFonts: [{
family: 'MyBrandFont',
weights: [
{ weight: 400, url: 'https://cdn.example.com/mybrand-regular.woff2' },
{ weight: 700, url: 'https://cdn.example.com/mybrand-bold.woff2' },
],
}]
}
```
#### System Fonts
```tsx theme={null}
theme={{
fontFamily: {
label: 'system-ui',
body: '-apple-system',
data: 'ui-monospace',
}
}}
```
#### FontFamily
| Property | Type | Description |
| -------- | ---------------------------- | ------------------------------- |
| `label` | `string \| FontFamilyConfig` | Font for headings and labels |
| `body` | `string \| FontFamilyConfig` | Font for body text |
| `data` | `string \| FontFamilyConfig` | Font for numeric/monospace data |
#### FontsConfig
| Property | Type | Description |
| ------------- | ------------------- | ---------------------------------- |
| `googleFonts` | `GoogleFontsConfig` | Google Fonts loading configuration |
| `customFonts` | `CustomFont[]` | Custom font definitions |
#### FontFamilyConfig
| Property | Type | Description |
| --------- | ---------------------------------- | --------------------------- |
| `family` | `string` | Font family name (required) |
| `weights` | `{ base?: number; bold?: number }` | Font weight configuration |
The `bold` weight in `weights` is only supported for the `data` role.
#### GoogleFontsConfig
| Property | Type | Description |
| ---------- | --------------------------------------------------------- | --------------------------------------------------------------------- |
| `families` | `string[]` | Font families with weights (e.g., `'Roboto:wght@400;700'`) (required) |
| `display` | `'auto' \| 'block' \| 'swap' \| 'fallback' \| 'optional'` | Font display strategy |
#### CustomFont
| Property | Type | Description |
| --------- | ----------------------------------- | ---------------------------------------------- |
| `family` | `string` | Font family name (required) |
| `url` | `string` | Single woff2 font URL (weight defaults to 400) |
| `weights` | `{ weight: number; url: string }[]` | Multiple weight definitions |
Either `url` or `weights` must be provided for custom fonts.
## Widget Features
Toggle specific visual features of the widget on or off.
| Property | Type | Description |
| ------------------- | --------- | ----------------------- |
| `headerIcons` | `boolean` | Show header icons |
| `headerBackground` | `boolean` | Show header background |
| `background` | `boolean` | Show widget background |
| `outlineComponents` | `boolean` | Show component outlines |
```tsx theme={null}
```
## Advanced Overrides
For complete control, use the `overrides` property to customize specific theme values. This allows you to override any part of the generated theme.
```tsx theme={null}
```
These types are used when customizing advanced theme overrides.
#### StatusColors
There are 4 types of statuses: info, warning, success, and failure.
| Property | Type | Description |
| ------------ | -------- | ------------------------------------------- |
| `main` | `string` | Main status color (hex format) |
| `foreground` | `string` | Text color for status elements (hex format) |
| `light` | `string` | Lighter variant (hex format) |
| `dark` | `string` | Darker variant (hex format) |
#### InteractiveColors
| Property | Type | Description |
| ---------- | -------- | ----------------------------------------- |
| `active` | `string` | Color when element is active (hex format) |
| `hover` | `string` | Color on hover (hex format) |
| `inactive` | `string` | Color when inactive (hex format) |
| `disabled` | `string` | Color when disabled (hex format) |
| `contrast` | `string` | Contrasting text/icon color (hex format) |
#### InteractiveThemeColors
| Property | Type | Description |
| ----------- | ---------------------------------------- | -------------------------------------- |
| `primary` | `InteractiveColors` | Primary interactive element colors |
| `secondary` | `InteractiveColors` | Secondary interactive element colors |
| `tertiary` | `InteractiveColors` | Tertiary interactive element colors |
| `input` | `{ active?: string; inactive?: string }` | Input field border colors (hex format) |
#### Theme Object Structure
The complete theme object structure for advanced overrides. All properties are optional.
| Property | Type | Description |
| ------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------- |
| `brand` | `string` | Brand accent color (hex format) |
| `background` | `{ main?: string; layer1?: string; layer2?: string; layer3?: string }` | Background colors for elevation layers |
| `text` | `{ primary?: string; secondary?: string; disabled?: string }` | Text colors |
| `interactive` | `InteractiveThemeColors` | Interactive element colors |
| `status` | `StatusColors` | Status indication colors (info, warning, success, failure) |
| `misc` | `{ divider?: string; footer?: string; skeleton?: string; highlight?: string }` | Miscellaneous UI colors |
| `shadows` | `{ bottom?: string; around?: string }` | Shadow CSS values |
All color values should be provided in hex format (e.g., `#RRGGBB` or `#RGB`).
# What are Rollups?
Source: https://docs.caldera.xyz/rollup-engine/about/about-rollups
Rollups are a Layer 2 scaling solution designed to enhance the scalability and efficiency of blockchain networks. In short: rollups are blockchains that rely on another layer-one blockchain (especially Ethereum) for settlement, while providing better scalability and performance guarantees compared to the underlying blockchain.
Here's a breakdown:
### Bundling Transactions
Rollups work by aggregating or "rolling up" multiple transactions into a singular transaction or a batch. This process occurs on a separate Layer 2 blockchain, which is a secondary framework built atop the primary (Layer 1) blockchain.
### Off-chain Execution
The execution of transactions is performed off-chain in rollups, thereby reducing the data that needs to be posted to the main blockchain. This is particularly beneficial in congested blockchain networks where the high volume of transactions can lead to slower processing times and higher fees.
### Posting to Layer 1
Once the transactions have been bundled and executed off-chain, a single transaction or a summary of the batch is posted to the main (Layer 1) blockchain. This action retains the security features of the primary blockchain while significantly reducing the data load, as only the rolled-up transaction is recorded on-chain.
# Optimistic Rollups
You can deploy [Arbitrum Nitro](/about/nitro) and [OP Stack](/about/bedrock) rollups via Caldera -- both of these stacks are "Optimistic" rollups.
The term "optimistic" in Optimistic Rollups comes from the optimistic assumption that transactions within a rollup are valid. In the "happy path" where the rollup is acting honestly, no on-chain proof of correctness is required. However, if the rollup sequencer acts maliciously or errantly, a "fault proof" can be submitted to the L1 and prevent incorrect execution from occuring.
Want to learn more about Optimistic Rollups? View [this article](https://ethereum.org/en/developers/docs/scaling/optimistic-rollups)
from ethereum.org
# Zero-Knowledge Rollups
You can deploy [ZK Stack](/about/zksync) and [Polygon CDK](/about/polygon) rollups via Caldera as well -- both of these stacks are "Zero-Knowledge" (aka ZK) rollups.
In contrast to optimistic rollups, ZK rollup nodes must submit a validity proof for verification to update state.
The validity proof is a cryptographic assurance that the state-change proposed by the rollup is really the result of executing the given batch of transactions. This means that ZK-rollups only need to provide validity proofs to finalize transactions on Ethereum instead of posting all transaction data on-chain like optimistic rollups.
To learn more about ZK Rollups, view [this article](https://ethereum.org/en/developers/docs/scaling/zk-rollups/)
from ethereum.org
# Alternative Data Availability
Source: https://docs.caldera.xyz/rollup-engine/about/alternative-da
This is a beta feature. Want to get started? [Get in touch](https://calendly.com/james_caldera/30min?utm_source=doc).
Caldera supports Alternative Data Availability (Alt-DA) via integrations with [Celestia](https://docs.celestia.org/learn/how-celestia-works/data-availability-layer), [Near](https://near.org/data-availability), and [Arbitrum Anytrust](https://arbitrum.io/anytrust)
# Why Alternative DA?
In order to ensure invalid transactions processed can be caught and reverted on a rollup, users need a way to make sure that the rollup's block data is actually published.
Right now, the vast majority of Ethereum rollups solve this by simply posting all of the rollup blocks onto Ethereum and relying on it for data availability.
But, traditional Ethereum DA can lead to extremely high and volatile costs, as rollups are forced to compete for limited blockspace with all other dApps and users transacting on Ethereum.
As a result, over 95% of the cost of a rollup transaction today comes from posting data to Ethereum.
# How it Works
Check out [our blog post](https://blog.caldera.xyz/alternative-data-availibility-for-approllups/)
for an in-depth explanation
Alternative DA systems use innovative approaches to separate out data availability from a chain's settlement, dramatically lowering associated costs and increasing throughput to significantly improve rollups' long-term scalability.
At the moment, we're proud to offer Celestia and Near as our current Alt-DA solutions for all Caldera Chains (and plan to integrate with other Alt-DA providers in the future), leveraging their novel technologies to save significant costs for the chains in our ecosystem.

# Build with Alternative DA
We're excited to work with teams exploring rollups with alternative data availability. If you're interested, please [get in touch](https://calendly.com/james_caldera/30min?utm_source=doc)!
# Optimism Bedrock
Source: https://docs.caldera.xyz/rollup-engine/about/bedrock
For a closer look, check out [Optimism's Documentation](https://stack.optimism.io/)
With Caldera, you can deploy dedicated rollups using the **OP stack** (Optimism Bedrock).
The OP stack is a battle-tested Optimistic Rollup stack. The OP stack powers *Optimism Mainnet* and *Base*, Coinbase's recently-launched L2. Collectively, the OP stack secures over \$3.5 Billion in TVL.
### Benefits
* 10-100x cheaper transactions compared to Ethereum.
* Ethereum equivalence, with full support for Ethereum smart contracts and developer tooling
* Fast block times (2s per block)
* Optional support for further cost reduction via Celestia DA
* Extremely permissive (MIT) licensing
* Ability to opt into the [Superchain](https://stack.optimism.io/docs/understand/explainer/), Optimism's future network of chains that share bridging, governance, and interoperability
# The Superchain
For more info, view the Superchain explainer [here](https://stack.optimism.io/docs/understand/explainer/)
The Optimism Superchain is envisioned as a network of interconnected chains on the Optimism protocol, enhancing scalability and interoperability among Layer 2 blockchain networks. The Superchain aims to unify the Optimism Mainnet and other OP stack chains into a single connected network, facilitating shared features like bridging, decentralized governance, and a communication layer. This setup is designed to allow individual chains to operate cohesively, promoting seamless communication and transactions among them.
The Superchain design is still early. We recommend consulting Optimism's documentation for the most up-to-date design.
# Guardian Nodes
Source: https://docs.caldera.xyz/rollup-engine/about/guardian-node
Caldera’s Guardian Node system introduces the first production-ready system where third parties are able to verify rollup blocks in exchange for rewards. This system introduces a novel “light verifier” for Arbitrum rollups which allows Guardian Node operators to verify Nitro batches on everyday hardware without needing to run a full Arbitrum node.
By focusing on reducing barriers to verify the network and distributing incentives, Caldera’s Guardian Node system improves the resilience and security of Arbitrum rollups.
## The Benefits
1. **Revenue Source**: A significant go-to-market benefit is that a project can use Guardian Nodes as a source of revenue. HYCHAIN, which launched its Guardian Node system with Caldera’s tooling, sold \~16k node keys within 2 weeks, raising \~2000 ETH. The sale period will continue for a duration of 3 years which will provide a steady revenue stream.
2. **Decentralization**: EVM rollups have all but solved the scalability problem, with L2s and L3s on Ethereum enabling virtually infinite scale. But previously, there was still no incentive for honest network participants to monitor these rollups. Guardian Nodes allow teams to decentralize their rollups by enabling users to verify blocks and secure the network in exchange for rewards.
3. **Token Demand**: By enabling more parties to watch over a rollup and identify malicious behavior, the network’s security grows more robust— a crucial step to establishing trust in the chain’s correctness. This in turn generates more demand for a rollup’s native token, which is required for users to participate in validation and helps provide practical cryptoeconomic security for the network.
# Native Gas Token
Source: https://docs.caldera.xyz/rollup-engine/about/native-token
With Caldera Chains, you can deploy Arbitrum and ZKsync rollups with a custom native gas token.
### What tokens can I use?
You can use almost any `ERC-20` token. as your rollup's native token. This includes your protocol tokens, or stablecoins such as USDC or DAI.
The only tokens that cannot be used as rollup native tokens are [elastic tokens](https://academy.binance.com/en/articles/elastic-supply-tokens-explained) due to their volatile supply. Thankfully, very few tokens employ this type of design.
It is a [requirement](https://docs.arbitrum.io/launch-arbitrum-chain/configure-your-chain/common-configurations/use-a-custom-gas-token-rollup#requirements-of-the-custom-gas-token) that your native gas token is a standard `ERC-20` token.
# Arbitrum Nitro
Source: https://docs.caldera.xyz/rollup-engine/about/nitro
For a closer look, check out [Arbitrum's Documentation](https://docs.arbitrum.io/inside-arbitrum-nitro)
With Caldera, you can deploy dedicated rollups using the **Arbitrum Nitro** stack.
Arbitrum Nitro is a battle-tested Optimistic Rollup stack. Arbitrum Nitro powers *Arbitrum One*, the flagship Arbitrum chain, and *Arbitrum Nova*, a lower-cost chain targeted towards gaming. Arbitrum Nitro secures over \$6 Billion in TVL across chains in production.
### Benefits
* 10-100x cheaper transactions compared to Ethereum.
* Ethereum equivalence, with full support for Ethereum smart contracts and developer tooling
* Faster block times, as fast as 250ms when under high throughput
* Working fault proofs
* Optional Support for WASM smart contracts via Stylus
* Support for further cost reduction via Arbitrum Anytrust or Celestia DA
* Ability to choose your rollup's native token
# Anytrust
For more info, view the Anytrust docs [here](https://docs.arbitrum.io/inside-arbitrum-nitro/#inside-anytrust)
Arbitrum AnyTrust, a variant of Arbitrum Nitro technology, adopts a mild trust assumption to lower transaction costs. Unlike standard Arbitrum where all nodes require access to every Layer 2 transaction data, AnyTrust relies on a Data Availability Committee (DAC) to store and provide data on demand, assuming at least two members are trustworthy for data availability. It employs Data Availability Certificates (DACerts) to guarantee data availability until a specified expiration time.
With Anytrust, you can achieve a further **10-100x** cost decrease compared to a standard rollup.
This setup allows for more cost-effective transaction processing while ensuring data availability, aiding in creating personal AnyTrust and Rollup chains with an infrastructure capable of significantly higher capacity than Ethereum, yet still leveraging Ethereum's security framework.
# Stylus
For more info, view the Stylus docs [here](https://docs.arbitrum.io/stylus/stylus-gentle-introduction)
Arbitrum Stylus is an advancement to the Arbitrum Nitro technology, introducing a secondary, co-equal WASM virtual machine alongside the existing Ethereum Virtual Machine (EVM) on the Arbitrum chains like Arbitrum One, Arbitrum Nova, and Arbitrum Orbit. This new virtual machine enhances the programming environment, enabling developers to write and deploy smart contracts using languages like Rust, C, or C++.
WASM execution is significantly more performant (Over **10x less gas used**) and allows developers to use battle-tested Rust, C++, and C libraries in their smart contracts.
Check out the OffchainLabs/*Awesome-Stylus* repo on Github for examples of
smart contracts with Stylus
# Reliability
Source: https://docs.caldera.xyz/rollup-engine/about/reliability
### Uptime SLAs
For all mainnet deployments, Caldera offers a 99.99% uptime SLA.
### Industry Standard Best Practices
At Caldera, we employ industry-standard best practices to ensure the reliability and availability of our services. Our Kubernetes configurations are designed with a high availability setup to mitigate service disruptions and maintain a resilient infrastructure. By adhering to recognized standards and best practices, we are able to provide a robust and reliable environment for our operations and, by extension, our partners.
All Caldera infrastructure is hosted in Amazon Web Services, and split across multiple regions. Our Kubernetes configuration is designed with reliability in mind: we auto-failover in the case of sequencers going down, and we autoscale our infra when traffic spikes.
### L1 RPC Fallback
One of the "weak links" in rollup operation is the connection to a layer-one (Ethereum mainnet) full node. If this connection is severed for an extended period of time, the rollup cannot function properly.
To further bolster our reliability, we have established a proxy load-balancing service to derisk potential challenges posed by L1 RPC outages. This proxy service aggregates over multiple top RPC providers, and re-routes our traffic in the event of downtime. This layer of protection helps in maintaining uninterrupted service and ensuring that our systems remain accessible and functional even during external disruptions in the broader network.
### Transparent Status Page
We believe in full transparency when it comes to system performance and availability. Every mainnet deployment comes with a status page, powered by [Betterstack](https://betterstack.com). Our status page provides real-time updates on each rollup, allowing you to subscribe and stay informed about the operational status of our services.
In the event of downtime, all members of the Caldera engineering team are alerted.
### Response SLAs and Escalation Procedures
Timely response and resolution are crucial for maintaining a high level of service reliability.
We have defined Service Level Agreements (SLAs) to ensure prompt responses to incidents and issues, **24 hours a day, 7 days a week**. Our SLAs outline the expected response times and resolution procedures, providing a clear framework for addressing concerns. Additionally, we have an escalation procedure in place for operational and arbitration scenarios, ensuring that critical issues receive the necessary attention and are resolved expediently.
# Security
Source: https://docs.caldera.xyz/rollup-engine/about/security
### Multisig Ownership of Mainnet Rollup Contracts
Security is paramount when dealing with blockchain contracts, especially when customer funds are involved. At Caldera, we employ multi-signature (multisig) ownership for our mainnet rollup contracts.
This means that multiple signatures are required to authorize any significant actions, providing an additional layer of security. With multisig ownership, **we ensure that customer funds remain protected, even in the unlikely event that our systems are compromised**.
### Using battle-tested, audited rollup stacks
Caldera only runs the most battle-tested rollup stacks, including Optimism, Arbitrum, and the Polygon CDK. Each of these stacks secures millions to billions of dollars in value, on production mainnets.
### Dual Authorization for Production Infrastructure Access
All Caldera production infrastructure is locked under a dual-authorization scheme. This process mandates that no single individual can access or modify the production environment without a second person from the company signing off on the action. This dual authorization ensures that there are checks and balances in place, significantly reducing the risk of unauthorized or malicious activity within our production infrastructure.
# Decentralized Sequencing
Source: https://docs.caldera.xyz/rollup-engine/about/shared-sequencing
This is a beta feature. Want to get started? [Get in touch](https://calendly.com/james_caldera/30min?utm_source=doc).
Caldera supports Decentralized Sequencing via an integration with [Espresso](https://www.espressosys.com/), a premier decentralized sequencing network.
# Why Decentralized Sequencing?
Every rollup relies on a sequencer to order and verify the transactions on the chain. Traditionally, these sequencers have been centralized entities, controlled by a single party or group of parties. The vast majority of rollups currently in production (including Arbitrum One, Optimism mainnet, Base, and zkSync, among others) currently utilize a centralized sequencer.
These rollups are still able to inherit the security properties of their underlying chain via rollup proof systems, but their centralized sequencers still pose several problems:
* Centralized sequencers create a single point of failure in the system. If the sequencer goes down, it can become impossible or prohibitively expensive to submit transactions for inclusion
* The centralized sequencer can arbitrarily censor or delay transactions, or reorder transactions to extract MEV
* Users do not have visibility into how transactions are ordered
The status quo requires users to place some trust in rollup operators: users must trust that the operator will keep the sequencer online, trust that the sequencer orders transactions according to spec, and trust that the operator is not extracting MEV from the chain or arbitrarily censoring transactions.
# How it Works
Check out [Espresso's documentation](https://docs.espressosys.com/sequencer/releases/cortado-testnet-release/op-stack-integration)
for an in-depth explanation
At a high level, the Espresso Sequencer network replaces the rollup's mempool implementation. User transactions are sent to the Espresso Sequencer rather than the rollup node itself. Then, rollup nodes query sequenced transactions from Espresso's sequencer node. This eliminates the dependence on a centralized sequencer to act fairly.

# Integrate with Espresso
We're excited to work with teams exploring rollups with decentralized sequencing. Please [get in touch](https://calendly.com/james_caldera/30min?utm_source=doc)!
# Bridged USDC
Source: https://docs.caldera.xyz/rollup-engine/about/usdc
Leverage Circle's Bridged USDC Standard for [OP Bedrock](/about/bedrock) and [Arbitrum Nitro](/about/nitro.mdx) rollups with Caldera. Bridged USDC provides benefits for blockchains, developers, and users alike, catalyzing activity on new blockchain networks and simplifying any future transition to native USDC.
## For Blockchains
Get bridged USDC into the hands of developers and users early with the potential for a seamless upgrade to native issuance in the future, thereby avoiding the time-consuming liquidity migration process of educating and incentivizing your ecosystem to move from bridged to native USDC.
## For developers
Build on bridged USDC with a contract address that will persist after an upgrade to native, no code change needed. Provide users a way to store, pay, trade, borrow and lend with bridged USDC that automatically becomes native upon an upgrade. No need to swap to a new asset.
# ZK Stack
Source: https://docs.caldera.xyz/rollup-engine/about/zksync
Full ZK Stack support is here! If you're interested in deploying a ZK Stack hyperchain with Caldera today, [contact us](https://calendly.com/james_caldera/30min?utm_source=docs)!
The ZK Stack is a modular, open-source framework designed to build custom ZK-powered hyperchains leveraging zkSync infrastructure.
At its core, the ZK Stack offers two key features: sovereignty and seamless connectivity. Each ZK Stack hyperchain operates completely independently, relying solely on Ethereum L1 for their liveness and security, while supporting a shared bridge to facilitate the interconnection of every hyperchain, thereby enabling trustless, fast (within minutes), and inexpensive (cost of a single transaction) interoperability.
### Benefits
* Ultra-low gas fees compared to Ethereum.
* Ethereum compatibility, with full support for Ethereum smart contracts and developer tooling
* Native account abstraction
* Native cross-chain composability via hyperbridges
* Support for further cost reduction via alternative DA solutions
* Ability to choose your rollup's native token
# Hyperchains
For more info, view zkSync's hyperchain docs [here](https://docs.zksync.io/zk-stack/concepts/hyperchains-hyperscaling.html)
Hyperchains are fractal-like instances of zkEVM running in parallel and with common settlement on the L1 mainnet. The name Hyperbridge comes from the traditional web, where users can navigate websites seamlessly using hyperlinks. Similarly, ZK Stack rollups are connected seamlessly via Hyperbridges.
Each Hyperchain is powered by the same zkEVM engine available on the ZK Stack (and currently powering the first hyperchain, zkSync Era). All the ZKP circuits thus remain 100% identical, allowing Hyperchains to fully inherit their security from the L1 regardless of deployer, which ensures zero additional trust/security assumptions.
# Foundry
Source: https://docs.caldera.xyz/rollup-engine/deploying-contracts/foundry
Deploying Smart Contracts using Foundry
## What is Foundry?
Foundry is a toolset for Ethereum development written in Rust that assists developers in managing dependencies, compiling projects, running tests, deploying contracts, and interacting with blockchains through the command line interface.
Additionally, Foundry can directly communicate with Caldera's Ethereum API, enabling the use of Foundry to deploy smart contracts into the Caldera network.
## Get Started with Foundry
1. Install Foundry
* Linux or MaxOS
```
curl -L https://foundry.paradigm.xyz | bash
foundryup
```
* Windows
```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs/ | sh
cargo install --git https://github.com/foundry-rs/foundry foundry-cli anvil --bins --locked
```
2. Create a project
```
forge init foundry
```
3. Navigate to the Source in the project and create your smart contract
```
cd src
touch MyToken.sol
```
4. Input your smart contract or use the sample contract below.
```solidity theme={null}
// SPDX-License-Identifier: MIT
// compiler version must be greater than or equal to 0.8.17 and less than 0.9.0
pragma solidity ^0.8.17;
contract HelloWorld {
string public greet = "Hello World!";
}
```
5. Install OpenZeppelin contracts as a dependency
```
forge install OpenZeppelin/openzeppelin-contracts
```
6. Compile contract
```
forge build
```
## Deploying Your Smart Contract
Deploying a contract with Forge is a simple process that can be done with a single command. However, it requires an RPC endpoint, a private key that has funds, and any arguments for the constructor of the contract.
For example, the `MyToken.sol` contract requires an initial supply of tokens to be specified in its constructor, so the command to deploy it on a network will include the argument of 100.
To deploy the `MyToken.sol` contract, use the command that corresponds to the Caldera chain's RPC URL while running the `forge create` command:
```
forge create --rpc-url "RPC URL" //Insert your RPC URL here
--constructor-args 100 \
--private-key YOUR_PRIVATE_KEY \
src/MyToken.sol:MyToken
```
# Hardhat
Source: https://docs.caldera.xyz/rollup-engine/deploying-contracts/hardhat
Deploying Smart Contracts using Hardhat
## What is Hardhat?
Hardhat is a development environment for Ethereum that helps developers manage and automate the common tasks involved in building smart contracts and decentralized applications.
It can directly interact with Caldera's Ethereum API, allowing for the deployment of smart contracts into the Caldera network.
Additionally, Hardhat is a comprehensive set of tools for creating Ethereum-based software, which includes various components that aid in editing, compiling, debugging, and deploying smart contracts and decentralized applications. All of these components work together to create a complete development environment.
## Creating a Hardhat Project
1. Create a directory for your project:
```
mkdir hardhat && cd hardhat
```
2. Initialize the project, which will create a `package.json` file
```
npm init -y
```
3. Install Hardhat
```
npm install hardhat
```
4. Create a project
```
npx hardhat
```
5. Create an empty `hardhat.config.js` and install the Ethers plugin to use the Ethers.js library to interact with the network.
```
npm install @nomiclabs/hardhat-ethers ethers
```
## Creating Your Smart Contract
1. Create a `contracts` directory
```
mkdir contracts && cd contracts
```
2. Create `your_contract.sol` file in `contracts` directory
```
touch your_contract.sol
```
## Creating Your Configuration File
Modify the Hardhat configuration file and create a secure file to store your private key in.
1. Create a `secrets.json` file to store your private key
```
touch secrets.json
```
2. Add your private key to `secrets.json`
```
{
"privateKey": "YOUR-PRIVATE-KEY-HERE"
}
```
3. Add the file to your project's `.gitignore`, and never reveal your private key.
4. Modify the `hardhat.config.js` file
* Import the Ethers.js plugin
* Import the `secrets.json` file
* Inside the `module.exports` add the Caldera network configuration
```javascript hardhat.config.js theme={null}
require('@nomiclabs/hardhat-ethers');
const { privateKey } = require('./secrets.json');
module.exports = {
solidity: "0.8.1",
defaultNetwork: "rinkeby",
networks: {
rinkeby: {
url: "https://eth-rinkeby.alchemyapi.io/v2/123abc123abc123abc123abc123abcde",
accounts: [privateKey]
},
caldera: {
url: "RPC URL", // Insert your RPC URL Here
}
},
}
```
## Deploying Your Smart Contract
1. Compile the contract
```
npx hardhat compile
```
2. Create a new directory for the script and name it scripts and add a new file to it called `deploy.js`
```
mkdir scripts && cd scripts
touch deploy.js
```
3. Create a deployment script, like the one below
```javascript scripts/deploy.js theme={null}
async function main() {
// 1. Get the contract to deploy
const Your_Contract = await ethers.getContractFactory('your_contract');
console.log('Deploying Your_Contract...');
// 2. Instantiating a new smart contract
const your_contract = await Your_Contract.deploy();
// 3. Waiting for the deployment to resolve
await your_contract.deployed();
// 4. Use the contract instance to get the contract address
console.log('Your_Contract deployed to:', your_contract.address);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
```
4. Deploy `your_contract.sol` using the command below
```
npx hardhat run scripts/deploy.js --network caldera
```
# Remix
Source: https://docs.caldera.xyz/rollup-engine/deploying-contracts/remix
Deploying Smart Contracts using Remix
## What is Remix?
Remix Project is a robust set of tools that can be used by individuals of any skill level throughout the entire process of developing contracts, and it also serves as an educational platform for learning and experimenting with Ethereum.
## Getting Started with Remix
1. Visit Remix to get started.
2. Under **Featured Plugins**, select **Solidity**.
3. Navigate to the **File Explorer** and click "**+**" to create a Smart Contract
4. Input your smart contract or use the sample contract below.
```solidity theme={null}
// SPDX-License-Identifier: MIT
// compiler version must be greater than or equal to 0.8.17 and less than 0.9.0
pragma solidity ^0.8.17;
contract HelloWorld {
string public greet = "Hello World!";
}
```
5. Navigate to the **Compile** sidebar option and click Compile.
## Deploying Your Smart Contract
Once you have written your Smart Contract in Remix, you can navigate to the sidebar option to Compile your contract.
1. Change the top **ENVIRONMENT** dropdown from "**Javascript**" to "**Injected Web3**"
2. This will take you MetaMask - Press connect in Metamask to allow Remix access.
3. Add your network to Metamask using these parameters from your Caldera Chain:
* Network
* New RPC URL
* Chain ID
* Currency Symbol
* Block Explorer URL
# Quickstart
Source: https://docs.caldera.xyz/rollup-engine/quickstart
Get started deploying a dedicated rollup, hosted by Caldera
## Testnet
To get started with a testnet environment, head to our dashboard and follow these steps:
1. Sign up or log in through the authorization page
2. Click "Get Started" from the **Manage Rollups** page
3. Select your rollup framework of choice ([Arbitrum Nitro](/about/nitro), [Optimism Bedrock](./about/bedrock), [zkSync's ZK Stack](./about/zkSync)), and then choose the *Testnet* network type on our **Deploy New Rollup** page
4. Select a native gas token and set relevant identifiers (Rollup Name, Subdomain, Chain ID)
5. Click the "Deploy New Rollup" button to launch your testnet rollup!
## Mainnet
1. [Book a demo](https://calendly.com/james_caldera/30min?utm_source=docs) to chat about your project's needs and why you're considering an app-rollup --
we'll brainstorm ways that we can help
2. Caldera will launch a rollup for you with the framework of your choice (Arbitrum Nitro, Optimism Bedrock, ZK Stack), and the parameters of your choice, on the chain of your choice (Ethereum, Polygon, Cronos, Optimism, Arbitrum, etc.)
3. Integrate your app with Caldera. Usually, it takes less than half an hour to port Ethereum apps to a Caldera chain. We're happy to help with this!
4. We'll let you know when your production-grade Mainnet rollup goes live!
# Block Explorer
Source: https://docs.caldera.xyz/rollup-engine/tools/block-explorer
Every Caldera Chain comes equipped with a user-friendly **Block Explorer** that allows for easy viewing of important data such as:
* Address balances
* Transaction history
* Verified contracts
* Smart contract code and execution
* Network statistics
* Mining information
Just search for an an address, token symbol, name, transaction hash, or block number to retrieve the on-chain information you're looking for.
Additionally, the block explorer's theme and styling can also be customized (through our integration with [Blockscout](https://www.blockscout.com/)) upon request to better fit the preferences of your users.
The explorer provides a valuable tool for both users and developers looking to better understand and interact with a blockchain,
providing transparency and accessibility to the inner workings of a blockchain. It can be used for a variety of purposes such as tracking transactions, monitoring smart contract execution, and analyzing network activity.
# Bridge UI
Source: https://docs.caldera.xyz/rollup-engine/tools/bridge-ui
Each Caldera Chain comes automatically deployed with a corresponding web-based **Bridge User Interface** that enables developers and users to deposit and withdraw assets to/from your Caldera Chain.
Our Bridge UI offers:
* Customizable branding, colors, and text copy on a per-rollup basis
* Seamless transfer of assets between your Caldera Chain and various public blockchains
* Clear, user-friendly interface
## What is a bridge?
A crypto bridge is a mechanism that allows for the transfer of assets between different blockchain networks.
This user-facing interface allows end-users to easily interact with the bridge and bring liquidity onto your rollup.
# Testnet Faucet
Source: https://docs.caldera.xyz/rollup-engine/tools/faucet
Caldera Chains come equipped a built-in **Testnet Faucet** that allows users to easily request, acquire, and test with the chain's native cryptocurrency token.
This feature is designed to make it easy for developers, testers, and new users to obtain small amounts of the native token to explore the functionality and features of the blockchain.
The faucet feature is typically configured to dispense small amounts of cryptocurrency to users who request it, allowing developers to test the functionality of the chain without having to make a purchase
and incurr any financial risk.
Additionally, faucets can serve as a useful tool for new testnet users to onboard onto your ecosystem and familiarize themselves with the fundamental functionality of your chain.
# Hub Page
Source: https://docs.caldera.xyz/rollup-engine/tools/hub-page
Caldera Chains all come with shareable **Hub Page** for both internal and external use, which provides one unified place
to access all essential user-facing tooling, including:
* Chain Details
* [Block Explorer](../tools/block-explorer)
* [Bridge UI](../tools/bridge-ui)
* [Testnet Faucet](../tools/faucet)
* Documentation
# Whitelabel Docs
Source: https://docs.caldera.xyz/rollup-engine/tools/whitelabel-docs
Each team building a Caldera Chain can request custom **Whitelabel Documentation**, created and written by us, to empower their developers,
educate their ecosystem, and support their end-users.
We're flexible with how we can provide this documentation. Some teams might want to closely integrate our app-rollup documentation into their own existing docs,
while others might want an entirely separate set of docs for their app-rollup.
We offer a set of markdown docs as well as an out-of-the-box frontend, and are happy to work with teams to ensure that their docs
suit the needs of their ecosystem's developers and community at-large.