npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wonderland/interop-cross-chain

v0.13.2

Published

Cross-chain interoperability library with standardized provider interface

Downloads

734

Readme

@wonderland/interop-cross-chain

[!CAUTION] Experimental release — not for production use.

This SDK is an early, preview release and has not been audited. It handles transaction and signature data for cross-chain value transfers, so a defect in the SDK could result in permanent, irrecoverable loss of user funds.

Do not use this SDK in production or with real user value.

The cross-chain package provides a standardized interface for interacting with cross-chain bridges and protocols. It enables seamless token transfers and swaps between different blockchain networks through a unified API.

Key features:

  • Cross-chain token transfers between supported networks
  • Cross-chain token swaps with customizable slippage
  • Quote fetching for cross-chain operations
  • Standardized provider interface for integrating different bridge protocols
  • Type-safe interactions with comprehensive TypeScript support
  • Step-based order model (signature and transaction steps)

Setup

  1. Install dependencies running pnpm install

Installation

viem is a peer dependency — install it alongside the package:

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

Supported viem range: ^2.35.0.

Available Scripts

Available scripts that can be run using pnpm:

| Script | Description | | ------------- | ------------------------------------------------------- | | build | Build library using tsc | | check-types | Check types issues using tsc | | clean | Remove dist folder | | lint | Run ESLint to check for coding standards | | lint:fix | Run linter and automatically fix code formatting issues | | format | Check code formatting and style using Prettier | | format:fix | Run formatter and automatically fix issues | | test | Run tests using vitest | | test:cov | Run tests with coverage report |

Usage

import type { QuoteRequest } from "@wonderland/interop-cross-chain";
import {
    createAggregator,
    createCrossChainProvider,
    getSignatureSteps,
    getTransactionSteps,
    isSignatureOnlyOrder,
} from "@wonderland/interop-cross-chain";
import { createWalletClient, http } from "viem";
import { sepolia } from "viem/chains";

const walletClient = createWalletClient({
    chain: sepolia,
    transport: http("https://..."),
    account: "0x...",
});

// Create providers for different protocols
const acrossProvider = createCrossChainProvider("across");
const relayProvider = createCrossChainProvider("relay");
const oifProvider = createCrossChainProvider("oif", {
    solverId: "my-solver",
    url: "https://...",
});
const bungeeProvider = createCrossChainProvider("bungee", {
    tier: "dedicated",
    apiKey: "your-api-key",
});

// Create aggregator with providers (can mix Across, Relay, OIF, Bungee, etc.)
const aggregator = createAggregator({
    providers: [acrossProvider, relayProvider, oifProvider, bungeeProvider],
});

// Get quotes using SDK QuoteRequest format
const quoteRequest: QuoteRequest = {
    user: "0xYourAddress",
    input: {
        chainId: 11155111,
        assetAddress: "0xTokenAddress",
        amount: "1000000000000000000",
    },
    output: {
        chainId: 84532,
        assetAddress: "0xOutputTokenAddress",
        recipient: "0xRecipientAddress",
    },
    swapType: "exact-input",
};

const response = await aggregator.getQuotes(quoteRequest);
const selectedQuote = response.quotes[0];

if (selectedQuote) {
    if (isSignatureOnlyOrder(selectedQuote.order)) {
        // Protocol mode: sign EIP-712 typed data (gasless for user)
        const step = getSignatureSteps(selectedQuote.order)[0];
        const { signatureType, ...typedData } = step.signaturePayload;
        const signature = await walletClient.signTypedData(typedData);
        await aggregator.submitOrder(selectedQuote, signature);
    } else {
        // User mode: execute transaction directly (user pays gas)
        const step = getTransactionSteps(selectedQuote.order)[0];
        await walletClient.sendTransaction({
            to: step.transaction.to,
            data: step.transaction.data,
            value: step.transaction.value ? BigInt(step.transaction.value) : undefined,
        });
    }
}

API

Providers

  • createCrossChainProvider(protocolName, config?) -- Create a provider for a supported protocol. Config is optional for Across, Relay, and Bungee (defaults to sandbox tier), required for OIF.
  • CrossChainProvider (abstract class)
    • .protocolName -- Returns the protocol name.
    • .providerId -- Returns the provider identifier.
    • .getQuotes(params: QuoteRequest) -- Fetch quotes for a cross-chain request.
    • .buildQuote(params: BuildQuoteRequest) -- Build a quote locally without calling a solver API.
    • .submitOrder(quote, signature) -- Submit a signed order to the provider.
    • .getTrackingConfig() -- Get configuration for order tracking.

Tracking Notes (Across)

  • Mainnet: fill tracking defaults to API-based polling via the Across API.
  • Testnet: fill tracking defaults to event-based watching (Across testnet API is not reliable).
  • The SDK still parses the origin-chain open event, so provide an origin-chain RPC URL for robust tracking.

Tracking Notes (Relay)

  • Relay tracking is fully API-based for both mainnet and testnet.
  • Both opened intent parsing and fill watching use the /intents/status/v3 endpoint.
  • No RPC URLs are required for Relay tracking.
  • Relay automatically notifies the solver of new deposits via the pre-tracker for faster indexing.

Aggregator

  • createAggregator(config) -- Create an aggregator for batch quoting and execution.
    • Config: { providers: CrossChainProvider[], sortingStrategy?, timeoutMs?, trackerFactory? }
  • Aggregator
    • .getQuotes(params: QuoteRequest) -- Get quotes from all providers. Returns { quotes: ExecutableQuote[], errors: GetQuotesError[] }.
    • .buildQuote(providerId, params: BuildQuoteRequest) -- Build a quote locally for a specific provider without calling a solver API.
    • .submitOrder(quote, signature) -- Submit a signed order.
    • .prepareTracking(providerId) -- Prepare order tracking for a provider.
    • .track(params) -- Track an existing transaction.
    • .getOrderStatus(params) -- Get current status without watching.

Asset Discovery

The SDK provides utilities to discover supported assets from providers. All discovery methods return a pre-processed DiscoveredAssets structure ready for consumption.

Via Aggregator (recommended):

import { createAggregator } from "@wonderland/interop-cross-chain";

const aggregator = createAggregator({ providers: [acrossProvider] });

// Discover assets from all configured providers
const discovered = await aggregator.discoverAssets({ chainIds: [1, 42161] });

// Get tokens for Ethereum using numeric chain ID
const ethTokens = discovered.tokensByChain[1];

// Get metadata for a specific token (nested by chainId then lowercase address)
const usdc = discovered.tokenMetadata[1]?.["0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"];
console.log(usdc?.symbol); // "USDC"
console.log(usdc?.decimals); // 6

Via individual service:

import { createAssetDiscoveryService } from "@wonderland/interop-cross-chain";

const service = createAssetDiscoveryService(provider);
if (service) {
    const discovered = await service.getSupportedAssets();
    const ethTokens = discovered.tokensByChain[1];
}

Key concepts:

  • Numeric chain IDs: Chain keys are plain numbers (e.g., 1 for Ethereum, 42161 for Arbitrum) — the same format used by viem and the rest of the SDK.
  • Plain addresses: All addresses in tokensByChain and tokenMetadata use standard 0x-prefixed format, ready for display or wallet interaction.
  • Nested metadata: tokenMetadata is nested by chain ID then lowercase address to prevent cross-chain address collisions.

Types:

  • DiscoveredAssets -- Aggregated discovery result with tokensByChain and tokenMetadata.
  • AssetInfo -- Token metadata: { address, symbol, decimals }.

Types

  • QuoteRequest -- SDK-friendly quote request with user, input, output, and swapType.
  • BuildQuoteRequest -- Request for local quote building with required amounts, escrowContractAddress, and fillDeadline.
  • Quote -- Quote with step-based order, preview, provider, latencyMs, and metadata.
  • ExecutableQuote -- Quote with provider context for submission.
  • Order -- Step-based order model with steps: (SignatureStep | TransactionStep)[].
  • InteropAccountId -- Chain-aware account identifier: { chainId: number, address: string }.

Step Helpers

  • getSignatureSteps(order) -- Extract signature steps from an order.
  • getTransactionSteps(order) -- Extract transaction steps from an order.
  • isSignatureOnlyOrder(order) -- Check if an order only requires signatures.
  • isTransactionOnlyOrder(order) -- Check if an order only requires transactions.

Bungee Provider

The Bungee Provider enables integration with the Bungee protocol for cross-chain swaps and bridging.

Configuration

import { createCrossChainProvider } from "@wonderland/interop-cross-chain";

const provider = createCrossChainProvider("bungee", {
    // API tier: "sandbox" (default, no auth), "dedicated" (API key), or "frontend" (domain whitelist)
    tier: "dedicated",
    apiKey: "your-api-key",

    // Fee configuration (shared across protocols)
    feeBps: "50", // 0.5% fee
    feeTakerAddress: "0xYourFeeAddress", // required when feeBps is set

    // Submission modes: "user-transaction" (onchain) or "gasless" (permit2)
    submissionModes: ["user-transaction"],

    // Optional
    slippage: "0.5", // 0.5% slippage tolerance
    refuel: true, // native gas on destination chain
    affiliateId: "your-affiliate-id",
    enableOtherProviders: true, // also return manual routes
    enableMultipleRoutes: true, // return several route alternatives per quote (default: false)
});

Manual Routes (Bungee)

With enableOtherProviders: true, getQuotes returns Bungee's auto routes plus one Quote per manual route — i.e. routes served by other bridges accessible through Bungee. Each manual route is built eagerly via GET /api/v1/bungee/build-tx so the quote ships with an executable TransactionStep. If one bridge's build-tx fails, the auto route and the remaining manual routes are still returned. The build response and the manual route entry are exposed on quote.metadata.bungeeBuildTx and quote.metadata.bungeeManualRoute.

Tracking Notes (Bungee)

  • Bungee tracking is fully API-based using the /api/v1/bungee/status endpoint.
  • Auto routes are tracked by requestHash (set as quote.tracking.orderId); manual routes have no requestHash and are tracked by the on-chain txHash instead.
  • Both opened intent parsing and fill watching use API polling with a 5-second interval.
  • No RPC URLs are required for Bungee tracking.

OIF Provider

The OIF Provider enables integration with any Open Intents Framework compliant solver.

Usage

import type { QuoteRequest } from "@wonderland/interop-cross-chain";
import {
    createCrossChainProvider,
    getSignatureSteps,
    getTransactionSteps,
    isSignatureOnlyOrder,
} from "@wonderland/interop-cross-chain";
import { createWalletClient, http } from "viem";
import { mainnet } from "viem/chains";

const walletClient = createWalletClient({
    chain: mainnet,
    transport: http("https://..."),
    account: "0x...",
});

// Create OIF provider with your solver endpoint
const provider = createCrossChainProvider("oif", {
    solverId: "my-solver",
    url: "https://...",
});

// Get quotes using SDK QuoteRequest
const quotes = await provider.getQuotes({
    user: "0xYourAddress",
    input: {
        chainId: 1,
        assetAddress: "0xTokenAddress",
        amount: "1000000",
    },
    output: {
        chainId: 42161,
        assetAddress: "0xOutputTokenAddress",
    },
    swapType: "exact-input",
});

const quote = quotes[0];
if (!quote) throw new Error("No quotes returned");

if (isSignatureOnlyOrder(quote.order)) {
    // Protocol Mode: Sign and submit order (gasless for user)
    const step = getSignatureSteps(quote.order)[0];
    const { signatureType, ...typedData } = step.signaturePayload;
    const signature = await walletClient.signTypedData(typedData);
    await provider.submitOrder(quote, signature);
} else {
    // User Mode: Execute transaction directly (user pays gas)
    const step = getTransactionSteps(quote.order)[0];
    await walletClient.sendTransaction({
        to: step.transaction.to,
        data: step.transaction.data,
        value: step.transaction.value ? BigInt(step.transaction.value) : undefined,
    });
}

Approval Requirements

Access approval info from the order checks:

// Get allowance requirements from order checks
const allowances = quote.order.checks?.allowances ?? [];
for (const { spender, tokenAddress, required } of allowances) {
    // Approve token spend if needed
}

Payload Validation

The SDK validates that calldata from solver APIs matches the user's intent. For Across, simple same-token bridges are fully validated (depositor, recipient, tokens, amount, chain). Cross-chain swap validation is coming soon.

References

The current SDK uses Across on testnet for demo purposes only. Performance may not reflect mainnet behavior and is not representative of the final production experience