Skip to main content
Integrate Para’s embedded wallets with Rhinestone SDK to build cross-chain smart accounts with intent-based transactions, automatic bridging, and gas abstraction across multiple EVM chains.

Prerequisites

Before integrating Para with Rhinestone, ensure you have:
  • Para API key from the Para Developer Portal
  • Rhinestone API key from the Rhinestone team
  • Node.js 18+ and Next.js development environment
  • Basic familiarity with React and TypeScript

Installation

Install the required dependencies:
npm install @getpara/react-sdk @rhinestone/sdk viem @tanstack/react-query

Setup Para Provider

Create a context provider that wraps your application:
"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
import React, { type ReactNode } from "react";

const queryClient = new QueryClient();

export default function ContextProvider({ children }: { children: ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <ParaProvider
        paraClientConfig={{
          apiKey: process.env.NEXT_PUBLIC_PARA_API_KEY as string,
          env: "BETA",
        }}
        config={{ appName: "Global Wallet Demo" }}
        paraModalConfig={{
          disableEmailLogin: false,
          authLayout: ["AUTH:FULL"],
          theme: { mode: "light" },
        }}
      >
        {children}
      </ParaProvider>
    </QueryClientProvider>
  );
}

Create Custom Hook

Create a hook to manage the Rhinestone account:
import { useState, useEffect, useCallback } from "react";
import { useWallet } from "@getpara/react-sdk";
import { useViemAccount } from "@getpara/react-sdk/evm/hooks";
import { RhinestoneSDK, wrapParaAccount } from "@rhinestone/sdk";
import type { Account } from "viem";

export function useGlobalWallet() {
  const { data: wallet } = useWallet();
  const { viemAccount } = useViemAccount();
  const [rhinestoneAccount, setRhinestoneAccount] = useState<any>(null);
  const [accountAddress, setAccountAddress] = useState<string | null>(null);

  useEffect(() => {
    async function init() {
      if (!viemAccount || !wallet?.id) return;

      const rhinestone = new RhinestoneSDK({
        apiKey: "proxy",
        endpointUrl: `${window.location.origin}/api/orchestrator`,
      });

      // Wrap Para account for signature compatibility
      const wrappedAccount = wrapParaAccount(viemAccount, wallet.id);

      // Create Rhinestone account
      const account = await rhinestone.createAccount({
        owners: {
          type: "ecdsa",
          accounts: [wrappedAccount as Account],
        },
      });

      setRhinestoneAccount(account);
      setAccountAddress(account.getAddress());
    }

    init();
  }, [viemAccount, wallet?.id]);

  const sendCrossChainTransaction = useCallback(
    async (sourceChains: any[], targetChain: any, calls: any[], tokenRequests: any[]) => {
      if (!rhinestoneAccount) throw new Error("Account not initialized");

      const transaction = await rhinestoneAccount.sendTransaction({
        sourceChains,
        targetChain,
        calls,
        tokenRequests,
        sponsored: true,
      });

      return await rhinestoneAccount.waitForExecution(transaction);
    },
    [rhinestoneAccount]
  );

  return {
    rhinestoneAccount,
    accountAddress,
    sendCrossChainTransaction,
  };
}

Setup API Orchestrator

Create an API route at app/api/orchestrator/[...path]/route.ts:
import { NextRequest, NextResponse } from "next/server";

const ORCHESTRATOR_URL = "https://v1.orchestrator.rhinestone.dev";

export async function POST(
  request: NextRequest,
  { params }: { params: Promise<{ path: string[] }> }
) {
  const apiKey = process.env.RHINESTONE_API_KEY;
  if (!apiKey) {
    return NextResponse.json({ error: "API key not configured" }, { status: 500 });
  }

  const path = (await params).path.join("/");
  const body = await request.text();
  
  const response = await fetch(`${ORCHESTRATOR_URL}/${path}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": apiKey,
    },
    body,
  });

  const responseBody = await response.text();
  return new NextResponse(responseBody, {
    status: response.status,
    headers: { "Content-Type": "application/json" },
  });
}

Send Cross-Chain Transactions

Use the hook in your component:
import { useGlobalWallet } from "@/hooks/useGlobalWallet";
import { arbitrum, base } from "viem/chains";
import { encodeFunctionData, parseUnits, erc20Abi } from "viem";

export function TransferComponent() {
  const { sendCrossChainTransaction, accountAddress } = useGlobalWallet();

  const handleTransfer = async () => {
    const transaction = await sendCrossChainTransaction(
      [arbitrum], // Source chains
      base,       // Target chain
      [{
        to: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // Base USDC
        value: BigInt(0),
        data: encodeFunctionData({
          abi: erc20Abi,
          functionName: "transfer",
          args: ["0xRecipient", parseUnits("10", 6)],
        }),
      }],
      [{
        address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        amount: parseUnits("10", 6),
      }]
    );
    
    console.log("Transaction:", transaction.fillTransactionHash);
  };

  return <button onClick={handleTransfer}>Send USDC</button>;
}

Key Features

This integration provides:
  • Cross-chain smart accounts: Single account across multiple EVM chains
  • Intent-based transactions: Automatic execution of complex cross-chain operations
  • Gas abstraction: Sponsored transactions without users managing gas fees
  • Automatic bridging: Seamless asset transfers between chains
  • Para wallet management: Embedded wallet infrastructure with MPC security

Complete Example

See the full working example with Para + Rhinestone:

Para + Rhinestone Example

View the complete working example in Para’s Examples Hub

Next Steps