Skip to main content

Overview

Para is an MPC wallet infrastructure that provides secure, non-custodial embedded wallets. This guide shows you how to integrate Para with Rhinestone smart accounts.
Para uses a different signature format (0/1 v-byte) than standard EVM wallets (27/28 v-byte). You must use wrapParaAccount to wrap Para signers before passing them to Rhinestone.

Prerequisites

Installation

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

Setup Para Provider

Create a context provider that wraps your application with Para and React Query. This setup enables Para’s authentication modal, wallet management, and proper React state handling.
"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";

// Set up queryClient
const queryClient = new QueryClient();

function ContextProvider({
  children,
}: {
  children: ReactNode;
}) {
  return (
    <QueryClientProvider client={queryClient}>
      <ParaProvider
        paraClientConfig={{
          apiKey: process.env.NEXT_PUBLIC_PARA_API_KEY as string,
          env: "BETA" as any,
        }}
        config={{
          appName: "Your App Name",
        }}
        paraModalConfig={{
          disableEmailLogin: false,
          disablePhoneLogin: true,
          authLayout: ["AUTH:FULL"],
          oAuthMethods: [],
          onRampTestMode: true, // Set to false in production
          theme: {
            foregroundColor: "#2D3648",
            backgroundColor: "#FFFFFF",
            accentColor: "#0066CC",
            darkForegroundColor: "#E8EBF2",
            darkBackgroundColor: "#1A1F2B",
            darkAccentColor: "#4D9FFF",
            mode: "light",
            borderRadius: "lg",
            font: "Inter",
          },
          recoverySecretStepEnabled: true,
          twoFactorAuthEnabled: false,
        }}
      >
        {children}
      </ParaProvider>
    </QueryClientProvider>
  );
}

export default ContextProvider;
Then wrap your application with this provider:
// app/layout.tsx (Next.js App Router)
import ContextProvider from './context-provider'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <ContextProvider>
          {children}
        </ContextProvider>
      </body>
    </html>
  )
}

Initialize Rhinestone with Para

The key is to wrap the Para viem account with wrapParaAccount before passing it to Rhinestone:
import { useEffect } 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 useRhinestoneAccount() {
  const { data: wallet } = useWallet()
  const { viemAccount } = useViemAccount()

  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 rhinestoneAccount = await rhinestone.createAccount({
        owners: {
          type: "ecdsa",
          accounts: [wrappedAccount as Account],
        },
      })

      console.log("Smart Account:", rhinestoneAccount.getAddress())
    }

    init()
  }, [viemAccount, wallet?.id])
}
Use a backend proxy for your Rhinestone API key in production.

Send Transactions

Once initialized, use the Rhinestone account for cross-chain transactions:
const transaction = await rhinestoneAccount.sendTransaction({
  sourceChains: [baseSepolia],
  targetChain: arbitrumSepolia,
  calls: [{
    to: "USDC",
    data: encodeFunctionData({
      abi: erc20Abi,
      functionName: "transfer",
      args: ["0xrecipient", parseUnits("10", 6)],
    }),
  }],
  tokenRequests: [{
    address: "USDC",
    amount: parseUnits("10", 6),
  }],
  sponsored: true,
})

const result = await rhinestoneAccount.waitForExecution(transaction)

Complete Example

See the full working example with Para + Rhinestone:

Next Steps