<!--
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: Full Example

This is the complete, copy-paste-runnable script for executing a cross-chain transfer end to end — provider and aggregator setup (with automatic ERC-20 approvals), quoting, execution, and the `main()` wrapper that ties it together, for both testnet and mainnet.

If you want each call explained step by step — plus native-token transfers, asset discovery, and multi-provider comparison — start with [Getting Started](/cross-chain/getting-started). This page is the assembled reference you can drop into a file and run.

## 1. Setup: Import Dependencies and Configure Environment

First, import the required libraries and set up your environment variables, such as your private key and a generic RPC URL.

```typescript
import {
    createAggregator,
    createApprovalService,
    createCrossChainProvider,
    isApprovalStep,
    PROTOCOLS,
} from "@wonderland/interop-cross-chain";
import { createPublicClient, createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { sepolia } from "viem/chains";

// Private key for the account to send the transactions
const PRIVATE_KEY = "";

// Configure your preferred RPC URL for Sepolia (or any supported chain)
const RPC_URL = process.env.RPC_URL || ""; // e.g., "https://sepolia.infura.io/v3/<API_KEY>"

const privateAccount = privateKeyToAccount(PRIVATE_KEY);
```

## 2. Initialize Blockchain Clients

Create public and wallet clients for interacting with the blockchain, using the generic RPC URL.

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

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

## 3. Set Up Cross-Chain Provider and Aggregator

Initialize the cross-chain provider and aggregator, which will handle quoting and executing cross-chain transfers. Wire an `approvalService` so the aggregator prepends any required ERC-20 `approve` steps to each quote automatically.

### Testnet (Sepolia → Base Sepolia)

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

const approvalService = createApprovalService({
    rpcUrls: {
        11155111: RPC_URL, // Sepolia
        84532: "https://base-sepolia.g.alchemy.com/v2/YOUR_API_KEY",
    },
});

const aggregator = createAggregator({
    providers: [acrossProvider, relayProvider],
    approvalService,
});
```

### Mainnet (Base → Arbitrum)

For mainnet, omit `isTestnet` (or set it to `false`) and use the corresponding mainnet chain IDs when building your clients (step 2), the approval service, and the quote request (step 4).

```typescript
const acrossProvider = createCrossChainProvider(PROTOCOLS.ACROSS);
const relayProvider = createCrossChainProvider(PROTOCOLS.RELAY);

const approvalService = createApprovalService({
    rpcUrls: {
        8453: RPC_URL, // Base
        42161: "https://arb-mainnet.g.alchemy.com/v2/YOUR_API_KEY",
    },
});

const aggregator = createAggregator({
    providers: [acrossProvider, relayProvider],
    approvalService,
});
```

## 4. Retrieve a Cross-Chain Quote

Request a quote for a cross-chain transfer using the SDK `QuoteRequest` format.

### Testnet example

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

### Mainnet example (Base → Arbitrum)

```typescript
const response = await aggregator.getQuotes({
    user: "0xYourAddress",
    input: {
        chainId: 8453, // Base
        assetAddress: "0xInputTokenAddress",
        amount: "100000000000000000", // 0.1 in wei
    },
    output: {
        chainId: 42161, // Arbitrum One
        assetAddress: "0xOutputTokenAddress",
        recipient: "0xRecipientAddress",
    },
    swapType: "exact-input",
});

if (response.errors.length > 0) {
    console.error("Errors:", response.errors);
}

if (response.quotes.length === 0) {
    console.error("No quotes available");
    return;
}
```

## 5. Execute the Cross-Chain Transaction

Because the aggregator was configured with an `approvalService` (step 3), each returned `quote.order.steps` already contains any ERC-20 `approve` transaction (a `TransactionStep` with `category: "approval"`) that the transfer needs, prepended before the transfer itself. Iterate the steps in order and handle each by `step.kind` — a single order can mix `transaction` steps (including prepended approval steps) and `signature` steps (gasless). On the first signature step, sign and submit, then stop: the solver takes the order from there.

```typescript
const quote = response.quotes[0];

// Iterate order.steps in emission order. approvalService prepends approval
// transactions onto signature-based quotes too, so a single order can mix
// transaction and signature steps — handle each by `step.kind`. On the first
// signature step, sign + submit and stop: the solver takes the order from
// there. (`submitOrder` currently forwards one signature per order;
// multi-signature orders aren't yet supported.)
for (const step of quote.order.steps) {
    if (step.kind === "transaction") {
        const { to, data, value, gas, maxFeePerGas, maxPriorityFeePerGas } = step.transaction;
        console.log(isApprovalStep(step) ? "Approving token…" : "Sending bridge tx…");
        const hash = await walletClient.sendTransaction({
            to,
            data,
            value: value ? BigInt(value) : undefined,
            gas: gas ? BigInt(gas) : undefined,
            maxFeePerGas: maxFeePerGas ? BigInt(maxFeePerGas) : undefined,
            maxPriorityFeePerGas: maxPriorityFeePerGas ? BigInt(maxPriorityFeePerGas) : undefined,
        });
        const receipt = await publicClient.waitForTransactionReceipt({ hash });
        if (receipt.status !== "success") {
            throw new Error(`Step failed: ${step.description ?? step.kind}`);
        }
        console.log("Confirmed: Success");
    } else {
        const { signatureType, ...typedData } = step.signaturePayload;
        const signature = await walletClient.signTypedData(typedData);
        await aggregator.submitOrder(quote, signature);
        console.log("Order submitted via signature");
        break;
    }
}
```

:::info\[Native token inputs]
Native token inputs (ETH, MATIC, etc.) never require approval, so no `approve` step is prepended. The approval service only enriches quotes whose `order.checks.allowances` lists an ERC-20 allowance that is below `required` on-chain.
:::

## 6. Run the Main Function

Finally, call the main function to execute the workflow.

```typescript
const main = async (): Promise<void> => {
    // ...all the above steps go here...
};

main().catch(console.error);
```

## Next steps

* [Order Tracking](/cross-chain/order-tracking) — monitor your transaction from initiation to completion
* [Concepts](/cross-chain/concepts) — understand intent-based architecture and ERC-7683
* [API Reference](/cross-chain/api) — complete function signatures and types
