Leverage Cross-Chain Swaps with Universal Bridge

Learn how to enable your users to swap from any asset to any other with thirdweb's Universal Bridge.

In this guide, we'll show you how to purchase 10 USDC on Optimism in Typescript.


  • Install the Connect SDK

    npm i thirdweb
  • Get Your Client ID

    Log in to the thirdweb dashboard. Click on Create New > Project to get your Client ID. You'll need your Client ID to interact with the Connect SDK.

  • Find available routes

    Before your user can select which tokens they'd like to swap, they'll need to find available routes.

    You can do this using the routes function in our Bridge namespace. You or your users can filter by origin and destination chains and/or tokens. Pagination is also built-in to the function.

    import { Bridge, NATIVE_TOKEN_ADDRESS } from "thirdweb";
    // Get all available routes
    const allRoutes = await Bridge.routes({
    client: thirdwebClient,
    });
    // Filter routes for a specific token or chain
    const filteredRoutes = await Bridge.routes({
    originChainId: 1, // From Ethereum
    originTokenAddress: NATIVE_TOKEN_ADDRESS,
    destinationChainId: 10, // To Optimism
    client: thirdwebClient,
    });
    // Paginate through routes
    const paginatedRoutes = await Bridge.routes({
    limit: 10,
    offset: 0,
    client: thirdwebClient,
    });

    This will return an array of Route objects, which will include information such as symbol, address, and chainId for both the origin and destination tokens.

  • Get a quote

    Once you know which routes are available, you can retrieve a quote to show the user how much they can expect to pay for a given swap.

    In this example, we'll use the Buy.quote function to get a quote for buying 10 USDC on Optimism for Base ETH.

    Quote allows us to get an expected amount before the user has connected their wallet. This quote won't come with executable transactions, and won't be a guaranteed price.

    import { Bridge, NATIVE_TOKEN_ADDRESS } from "thirdweb";
    const buyQuote = await Bridge.Buy.quote({
    originChainId: 8453, // Base
    originTokenAddress: NATIVE_TOKEN_ADDRESS,
    destinationChainId: 10, // Optimism
    destinationTokenAddress:
    "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85", // Optimism USDC
    amount: 10000000n, // 10 USDC
    client: thirdwebClient,
    });
    console.log(
    `To get ${buyQuote.destinationAmount} wei on destination chain, you need to pay ${buyQuote.originAmount} wei`,
    );

    This will return a Quote object, which will include the originAmount and destinationAmount in wei, along with some more useful information about the predicted quote.

  • Get the prepared transaction

    Now that we know how much the user can expect to pay, we can have them connect their wallet and execute the swap.

    To get a prepared quote, we'll use the Buy.prepare function. The key difference with this function is it requires a sender and receiver to be specified.

    import { Bridge, NATIVE_TOKEN_ADDRESS } from "thirdweb";
    const preparedBuy = await Bridge.Buy.prepare({
    originChainId: 8453, // Base
    originTokenAddress: NATIVE_TOKEN_ADDRESS,
    destinationChainId: 10, // Optimism
    destinationTokenAddress:
    "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85", // Optimism USDC
    amount: 10000000n, // 10 USDC
    sender: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709", // Your user's wallet address
    receiver: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709", // Recipient address (can be the same as sender)
    client: thirdwebClient,
    });
    // The prepared quote contains the steps and transactions you need to execute
    console.log(`Steps: ${preparedBuy.steps.length}`);

    This will return a PreparedQuote object. It will look very similar to the Quote you received in the previous step, but it will include a steps array containing all the transactions you need to execute to complete the swap.

  • Execute the swap

    To execute the swap, we'll need to send all transactions in each step one after the other. The SDK automatically includes any necessary approvals in the transactions array.

    import { sendAndConfirmTransaction } from "thirdweb";
    const preparedBuy = await Bridge.Buy.prepare({
    originChainId: 8453, // Base
    originTokenAddress: NATIVE_TOKEN_ADDRESS,
    destinationChainId: 10, // Optimism
    destinationTokenAddress:
    "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85", // Optimism USDC
    amount: 10000000n, // 10 USDC
    sender: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709", // Your user's wallet address
    receiver: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709", // Recipient address (can be the same as sender)
    client: thirdwebClient,
    });
    // Execute all transactions in sequence
    for (const step of preparedBuy.steps) {
    for (const transaction of step.transactions) {
    // Handle approvals first
    if (transaction.action === "approval") {
    const result = await sendAndConfirmTransaction({
    transaction,
    account: wallet.account,
    });
    console.log("Approval sent:", result.transactionHash);
    } else {
    // Execute the main swap transaction
    const result = await sendAndConfirmTransaction({
    transaction,
    account: wallet.account,
    });
    console.log("Swap transaction sent:", result.transactionHash);
    // Wait for completion before continuing
    let swapStatus;
    do {
    swapStatus = await Bridge.status({
    transactionHash: result.transactionHash,
    chainId: transaction.chainId,
    client: thirdwebClient,
    });
    if (swapStatus.status === "PENDING") {
    await new Promise((resolve) => setTimeout(resolve, 3000)); // Wait 3 seconds
    }
    } while (swapStatus.status === "PENDING");
    if (swapStatus.status === "FAILED") {
    throw new Error("Swap transaction failed");
    }
    }
    }
    }
  • Getting the swap status

    You can get the status of any swap using the transaction hash and chain ID of its origin transaction.

    When sending transactions in a prepared quote, you must use Bridge.status to confirm COMPLETED status before moving to the next transaction. This ensures both origin and destination transactions have completed successfully.

    import { Bridge } from "thirdweb";
    // Check the status of a bridge transaction
    const bridgeStatus = await Bridge.status({
    transactionHash:
    "0x5959b9321ec581640db531b80bac53cbd968f3d34fc6cb1d5f4ea75f26df2ad7",
    chainId: 137, // The chain ID where the transaction was initiated
    client: thirdwebClient,
    });
    // The status will be one of: "COMPLETED", "PENDING", "FAILED", or "NOT_FOUND"
    if (bridgeStatus.status === "COMPLETED") {
    console.log(`
    Bridge completed!
    Sent: ${bridgeStatus.originAmount} wei on chain ${bridgeStatus.originChainId}
    Received: ${bridgeStatus.destinationAmount} wei on chain ${bridgeStatus.destinationChainId}
    `);
    } else if (bridgeStatus.status === "PENDING") {
    console.log("Bridge transaction is still pending...");
    } else if (bridgeStatus.status === "FAILED") {
    console.log("Bridge transaction failed");
    } else {
    console.log("Transaction not found");
    }