Privy Integration
Open and close leveraged positions from a Privy wallet — an embedded EOA via the wagmi connector, or an ERC-4337 smart account via batched userOps.
A Privy embedded wallet is an EOA and ships with a wagmi connector, so it drops into the Direct EOA flow unchanged — the vault sees an ordinary msg.sender. Enabling Privy smart wallets instead makes msg.sender an ERC-4337 account; see Smart wallets.
Both flows are verified end-to-end in the demo UI (WalletProviders.tsx, config.privy.ts, ConnectControls.tsx).
1. Wrap your app
Use Privy's WagmiProvider (from @privy-io/wagmi), not wagmi's own — it wires the connector and auto-connect.
npm install @privy-io/react-auth @privy-io/wagmiimport {PrivyProvider} from "@privy-io/react-auth";
import {WagmiProvider, createConfig} from "@privy-io/wagmi";
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
import {http} from "wagmi";
import {polygon} from "wagmi/chains";
// No `connectors` — PrivyProvider injects the wallet connector.
const wagmiConfig = createConfig({
chains: [polygon],
transports: {[polygon.id]: http()},
});
const queryClient = new QueryClient();
export function Providers({children}: {children: React.ReactNode}) {
return (
<PrivyProvider
appId={import.meta.env.VITE_PRIVY_APP_ID}
config={{
defaultChain: polygon,
supportedChains: [polygon],
embeddedWallets: {ethereum: {createOnLogin: "users-without-wallets"}},
}}
>
<QueryClientProvider client={queryClient}>
<WagmiProvider config={wagmiConfig}>{children}</WagmiProvider>
</QueryClientProvider>
</PrivyProvider>
);
}appId is a public client identifier. Get it from the Privy dashboard.
2. Read the wallet address
The address that signs on-chain is the wallet_address you must quote for. After login, read it from wagmi:
3. Open and close
Each call is a wagmi writeContract, signed by Privy — identical to the Direct EOA flow.
The backend handles the rest — exchange order on open, proceeds on close, with position.opened / position.closed over WebSocket.
Smart wallets (Account Abstraction)
Enable Smart wallets in the dashboard and each user also gets an ERC-4337 account that becomes msg.sender. Two changes from the EOA flow:
Quote for the smart account.
wallet_addressisclient.account.address(the contract that signs), not the owner EOA.Submit via the smart-wallet client, batching approve + open into one userOperation.
Closing is the same with a single requestClose call.
A 4337 wallet needs a bundler (Privy dashboard). Use a keyed endpoint — https://api.pimlico.io/v2/137/rpc?apikey=<key>; the keyless public.pimlico.io blocks browser CORS. Add a paymaster for gasless opens; without one the smart account pays its own gas (fund it with POL — the first userOp also deploys it).
Verified end-to-end in the demo UI (contract/smartWalletHooks.ts, SmartWalletBridge in WalletProviders.tsx).
Notes
Funding.
useFundWalletopens Privy's on-ramp/transfer flow; or send pUSD and a little POL to the wallet directly.Export.
useExportWalletreveals the embedded key for self-custody.One switch. In the demo UI the whole RainbowKit ↔ Privy swap is gated on
VITE_PRIVY_APP_ID; the contract layer is untouched.
Last updated

