<!--
Sitemap:
- [Interop SDK Documentation](/index): Build multichain TypeScript apps with interoperable addresses, cross-chain quotes, transfer execution, and order tracking across providers.
- [Install Interop SDK](/installation): Install @wonderland/interop-addresses and @wonderland/interop-cross-chain, then choose the package that fits your multichain app.
- [Addresses Module](/addresses/): Parse, encode, and resolve chain-aware addresses that combine an account, chain, and optional ENS name into one unambiguous identifier.
- [Addresses: Getting Started](/addresses/getting-started): Parse an interoperable address and extract its components — go from a human-readable name like vitalik.eth@eip155:1 to address and chain ID.
- [Addresses: Concepts](/addresses/concepts): How EIP-7930, ERC-7828, and CAIP-350 combine address and chain into a single, unambiguous, validated identifier for multichain apps.
- [Parsing an Interoperable Name](/addresses/example): Walkthrough for wallet developers — extract the raw address and chain ID from an interop address so legacy contracts keep working.
- [Addresses: Advanced Usage](/addresses/advanced-usage): Advanced patterns for interoperable addresses — checksums, validation, error handling, and round-trip conversions between formats.
- [Addresses: API Reference](/addresses/api): Function signatures and types for the interop-addresses package — high-level helpers, name-layer methods, and binary-layer primitives.
- [Cross-Chain Module](/cross-chain/): One open source integration for cross-chain actions — compare quotes across providers, execute orders, and track completion.
- [Cross-Chain: Getting Started](/cross-chain/getting-started): Execute a cross-chain token transfer end-to-end — create a provider, fetch a quote, send the transaction, and track the order to completion.
- [Cross-Chain: Concepts](/cross-chain/concepts): The intent-based architecture behind the cross-chain package and how the SDK unifies heterogeneous bridge providers behind a common interface.
- [Supported Providers](/cross-chain/providers): Supported cross-chain providers (Across, Relay, OIF, Bungee, LiFi Intents) and how to configure each via createCrossChainProvider.
- [Across Provider](/cross-chain/across-provider): Configure and use the Across Protocol provider for cross-chain token transfers via the Across bridge infrastructure.
- [Relay Provider](/cross-chain/relay-provider): Configure and use the Relay Protocol provider for cross-chain transfers, including opt-in gasless execution via EIP-3009 signatures.
- [OIF Provider](/cross-chain/oif-provider): Direct integration with any OIF-compliant solver — submission modes, resource locks, and configuration for Open Intents Framework backends.
- [Bungee Provider](/cross-chain/bungee-provider): Cross-chain token transfers via Bungee — onchain transactions, gasless permit2 flow, and tier-based API access for sandbox or production.
- [LiFi Intents Provider](/cross-chain/lifi-intents-provider): Cross-chain transfers through the LI.FI intent solver marketplace, where competing solvers fulfill deposits at the best available rate.
- [Cross-Chain: Full Example](/cross-chain/example): End-to-end example of executing a cross-chain transfer — setup, quote, approval handling, transaction submission, and order tracking.
- [Cross-Chain: Frontend Integration](/cross-chain/frontend-integration): Wire the cross-chain SDK into a React/Next.js app with wagmi v2 — a useCrossChainSwap hook covering quotes, approvals, and submission.
- [Order Tracking](/cross-chain/order-tracking): Track cross-chain orders from initiation to completion via OIF OrderStatus events, with both onchain and offchain observation strategies.
- [Cross-Chain: Advanced Usage](/cross-chain/advanced-usage): Aggregator patterns for cross-chain transfers — multi-provider quote fetching, sorting strategies, timeouts, and built-in order tracking.
- [Cross-Chain: API Reference](/cross-chain/api): Function signatures and types for the interop-cross-chain package — providers, aggregator, approval service, and order tracking.
-->

# Cross-Chain: Getting Started

:::tip\[Building a frontend?]
This guide uses `privateKeyToAccount` and a plain Node.js script to keep the flow focused on the SDK. If you're wiring the SDK into a React / Next.js app with an injected wallet, jump to [Frontend Integration](/cross-chain/frontend-integration) for the wagmi-based pattern.
:::

In this tutorial, you'll execute a cross-chain token transfer using the Interop SDK. By the end, you'll know how to create a provider, fetch a quote, send a transaction, and [discover which chains and tokens are supported](#which-chains-and-tokens-are-supported).

## Prerequisites

* Node.js v20.x or higher
* A private key with testnet funds
* An RPC URL for your origin chain (e.g., Sepolia)

## Install the package

`viem` is a peer dependency (`^2.35.0`) — install it alongside the package:

```bash
npm install @wonderland/interop-cross-chain viem
# or
yarn add @wonderland/interop-cross-chain viem
# or
pnpm add @wonderland/interop-cross-chain viem
```

## Create a provider

The SDK uses a factory pattern. Let's start with Relay on testnet:

```ts twoslash
import { createCrossChainProvider, PROTOCOLS } from "@wonderland/interop-cross-chain";

const provider = createCrossChainProvider(PROTOCOLS.RELAY, { isTestnet: true });
```

Examples throughout the docs use the `PROTOCOLS` constant (`PROTOCOLS.RELAY`, `PROTOCOLS.ACROSS`, `PROTOCOLS.OIF`, `PROTOCOLS.BUNGEE`, `PROTOCOLS.LIFI_INTENTS`) rather than the literal strings it maps to — it keeps the protocol name typo-safe and discoverable in your IDE.

Other available providers: [Across](/cross-chain/across-provider), [OIF](/cross-chain/oif-provider). See [Supported Providers](/cross-chain/providers) for the full list.

## Set up your wallet

You'll need [viem](https://viem.sh) clients to interact with the blockchain:

```typescript
import { createPublicClient, createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { sepolia } from "viem/chains";

const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const RPC_URL = "https://sepolia.infura.io/v3/YOUR_API_KEY";

const publicClient = createPublicClient({
    chain: sepolia,
    transport: http(RPC_URL),
});

const walletClient = createWalletClient({
    chain: sepolia,
    transport: http(RPC_URL),
    account,
});
```

## Fetch a quote

Request a quote for a cross-chain transfer:

```typescript
const quotes = await provider.getQuotes({
    user: account.address,
    input: {
        chainId: 11155111, // Sepolia
        assetAddress: "0xInputTokenAddress",
        amount: "100000000000000000", // 0.1 tokens in wei
    },
    output: {
        chainId: 84532, // Base Sepolia
        assetAddress: "0xOutputTokenAddress",
        recipient: account.address,
    },
    swapType: "exact-input",
});

const quote = quotes[0];
console.log(`Quote from ${quote.provider}`);
```

### Native tokens (ETH, MATIC, etc.)

To bridge a native asset, use `NATIVE_ASSET_ADDRESS` as the `assetAddress`:

```typescript
import { createCrossChainProvider, NATIVE_ASSET_ADDRESS } from "@wonderland/interop-cross-chain";

const quotes = await provider.getQuotes({
    user: account.address,
    input: {
        chainId: 11155111, // Sepolia
        assetAddress: NATIVE_ASSET_ADDRESS,
        amount: "100000000000000000", // 0.1 ETH in wei
    },
    output: {
        chainId: 84532, // Base Sepolia
        assetAddress: NATIVE_ASSET_ADDRESS,
        recipient: account.address,
    },
    swapType: "exact-input",
});
```

:::info
Both `0x0000000000000000000000000000000000000000` (zero address) and `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` ([EIP-7528](https://eips.ethereum.org/EIPS/eip-7528)) are accepted by the SDK as native asset sentinels. `NATIVE_ASSET_ADDRESS` exports the EIP-7528 form (`0xeeee...eeee`) and is the canonical constant used in all SDK examples.
:::

## Handle ERC-20 approvals

ERC-20 inputs need an `approve` before the transfer step. The SDK can do this for you: wire an `approvalService` into the aggregator and every returned quote already has the necessary `approve` `TransactionStep`s prepended to `order.steps`. Iterate the steps in order and each `approve` fires before the step that needs it.

See [Automatic ERC-20 Approvals](/cross-chain/advanced-usage#automatic-erc-20-approvals) for the setup, or the [Full Example](/cross-chain/example) for a complete runnable script.

## Execute the transaction

An order is a list of steps. Iterate `quote.order.steps` in emission order and handle each by its `kind`: send `transaction` steps with your wallet, or sign and submit `signature` steps (gasless). A single order can hold transaction steps, signature steps, or — when an `approvalService` is wired in — both (a prepended `approve` transaction followed by a signature). On the first signature step, sign, submit, and stop: the solver takes the order from there.

```typescript
for (const step of quote.order.steps) {
    if (step.kind === "transaction") {
        // User pays gas: send the transaction and wait for it to confirm.
        const hash = await walletClient.sendTransaction({
            to: step.transaction.to,
            data: step.transaction.data,
            value: step.transaction.value ? BigInt(step.transaction.value) : undefined,
        });
        console.log("Transaction sent:", hash);

        const receipt = await publicClient.waitForTransactionReceipt({ hash });
        if (receipt.status !== "success") {
            throw new Error(`Step failed: ${step.description ?? step.kind}`);
        }
        console.log("Confirmed: Success");
    } else {
        // Gasless: sign the EIP-712 payload and submit — the solver executes for you.
        const { signatureType, ...typedData } = step.signaturePayload;
        const signature = await walletClient.signTypedData(typedData);
        await provider.submitOrder(quote, signature);
        console.log("Order submitted via signature");
        break;
    }
}
```

## Which chains and tokens are supported?

Rather than hard-coding a supported-tokens list, ask the aggregator at runtime. `discoverAssets()` queries every configured provider in parallel and returns a pre-processed map keyed by numeric chain ID:

```typescript
const discovered = await aggregator.discoverAssets({ chainIds: [1, 8453] });

// Token addresses available on each chain
console.log(discovered.tokensByChain[1]); // Ethereum
console.log(discovered.tokensByChain[8453]); // Base

// Token metadata (nested by chain ID then lowercase address)
const usdc = discovered.tokenMetadata[1]?.["0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"];
console.log(usdc?.symbol, usdc?.decimals); // "USDC", 6
```

Omit `chainIds` to discover across every chain each provider supports. For a single-provider variant and the full `DiscoveredAssets` shape, see the [API Reference](/cross-chain/api#aggregator).

## Compare quotes from multiple providers

Use the `Aggregator` to fetch and sort quotes from multiple providers at once. For protocols whose config is optional (`across`, `relay`, `bungee`, `lifi-intents`) you can pass the protocol name directly and the aggregator creates the provider with defaults:

```typescript
import { createAggregator, PROTOCOLS } from "@wonderland/interop-cross-chain";

const aggregator = createAggregator({
    providers: [PROTOCOLS.ACROSS, PROTOCOLS.RELAY, PROTOCOLS.BUNGEE, PROTOCOLS.LIFI_INTENTS],
});

const response = await aggregator.getQuotes({
    /* same QuoteRequest as above */
});

console.log(`Got ${response.quotes.length} quotes`);
response.errors.forEach((err) => console.warn(`Provider error: ${err.errorMsg}`));
```

Need custom config — or a provider that requires it, like OIF — pass an instance instead. You can mix both forms:

```typescript
import {
    createAggregator,
    createCrossChainProvider,
    PROTOCOLS,
} from "@wonderland/interop-cross-chain";

const acrossProvider = createCrossChainProvider(PROTOCOLS.ACROSS, { isTestnet: true });

const aggregator = createAggregator({
    providers: [PROTOCOLS.RELAY, acrossProvider],
});
```

Each provider must have a unique `providerId`; passing two that resolve to the same id throws `DuplicateProvider`.

## Quick reference

### Execution flow

1. **Create provider** → `createCrossChainProvider(PROTOCOLS.ACROSS)` (or use `createAggregator` for multiple — wire an `approvalService` to enrich quotes with ERC-20 `approve` steps automatically)
2. **Get quotes** → `provider.getQuotes(request)` or `aggregator.getQuotes(request)`
3. **Execute** → iterate `quote.order.steps` and handle each by `kind` (see [the execute step above](#execute-the-transaction) — convert string `value` to `BigInt`):
   * **`transaction` (user pays gas):** send with `walletClient.sendTransaction()` — any prepended `approve` steps come first
   * **`signature` (gasless):** `signTypedData()` → `provider.submitOrder(quote, signature)`, then stop
4. **Track** → `createOrderTracker(provider)` for single-provider or `aggregator.track({ txHash, providerId, originChainId, destinationChainId })` for aggregator

### Which function should I use?

| I want to...                            | Use                                                                    |
| --------------------------------------- | ---------------------------------------------------------------------- |
| Get quotes from one provider            | `provider.getQuotes(request)`                                          |
| Get quotes from multiple providers      | `aggregator.getQuotes(request)`                                        |
| Build a quote locally (no provider API) | `aggregator.buildQuote(providerId, request)`                           |
| Submit a signed order                   | `provider.submitOrder(quote, signature)`                               |
| Check if order is gasless               | `isSignatureOnlyOrder(quote.order)`                                    |
| Get signature steps from an order       | `getSignatureSteps(quote.order)`                                       |
| Get transaction steps from an order     | `getTransactionSteps(quote.order)`                                     |
| Track an order (single provider)        | `createOrderTracker(provider)` → `tracker.watchOrder({ txHash, ... })` |
| Track an order (aggregator)             | `aggregator.track({ txHash, providerId, originChainId, ... })`         |
| Discover supported tokens               | `aggregator.discoverAssets()`                                          |

## Next steps

* [Order Tracking](/cross-chain/order-tracking) — monitor your transfer from initiation to completion
* [Supported Providers](/cross-chain/providers) — all providers and their configuration options
* [Concepts](/cross-chain/concepts) — understand intent-based architecture and ERC-7683
* [Advanced Usage](/cross-chain/advanced-usage) — sorting strategies, timeouts, error handling
* [API Reference](/cross-chain/api) — complete function signatures and types
