Account Abstraction
Account abstraction (AA) replaces traditional externally owned accounts (EOAs) with programmable smart contract accounts. This unlocks capabilities that EOAs alone cannot provide:
- Gas sponsorship — let users transact without holding native tokens for gas fees
- Batched transactions — bundle multiple operations into a single atomic transaction
- Session keys — grant temporary, scoped permissions without exposing the primary key
- Custom authorization — implement multi-factor auth, spending limits, or recovery logic at the account level
- Programmable accounts — create accounts with built-in rules for corporate or multi-user scenarios
Two standards are currently in use for AA on EVM-based chains:
| EIP-4337 | EIP-7702 |
|---|
| How it works | UserOperations processed by bundlers via an EntryPoint contract | EOA delegates to a smart contract via a type-4 transaction |
| Account address | New smart contract address (different from EOA) | Same as your EOA |
| Chain support | All EVM chains | Requires chain-level support |
| Infrastructure | Bundler + Paymaster | Provider-dependent |
| Gas overhead | Higher (extra validation steps) | Lower (native execution) |
| Maturity | Production-ready | Emerging |
| Best for | Maximum compatibility, dedicated smart wallet | Keeping EOA address, simpler flows |
Both standards support gas sponsorship and batched transactions.
Learn more about EIP-4337 and EIP-7702 on the Ethereum Improvement Proposals site.
Para Integrations
Para acts as the signer (EOA) that controls smart contract wallets — it is not a smart wallet itself. Para handles secure key management via MPC, while the AA provider deploys and manages the smart contract account on-chain. This means your users’ private keys remain secure and under their control regardless of which provider you choose.
Para wraps each provider in a shared SmartAccount interface. Whether you use EIP-4337 or EIP-7702 mode, your application code stays the same — you can swap providers or switch between standards without rewriting transaction logic.
Every provider integration is available as an action function (createXxxSmartAccount) — an imperative async function you can call anywhere, including outside React components, inside custom hooks, or in server-side code. React applications also get a hook (useXxxSmartAccount) — a declarative wrapper powered by React Query that handles initialization, caching, and automatic re-creation when config changes.
Both return the same SmartAccount object:
import type { Chain, Hex, LocalAccount, TransactionReceipt } from "viem";
interface SmartAccount {
smartAccountAddress: Hex; // On-chain account address
signer: LocalAccount; // Para viem signer
chain: Chain; // Configured chain
mode: "4337" | "7702"; // Account type
provider: string; // Provider name
// Send a single transaction and wait for receipt
sendTransaction(params: {
to: Hex;
value?: bigint;
data?: Hex;
}): Promise<TransactionReceipt>;
// Send batched transactions atomically
sendBatchTransaction(calls: Array<{
to: Hex;
value?: bigint;
data?: Hex;
}>): Promise<TransactionReceipt>;
client: any; // Provider-specific client for advanced usage
}
When using mode: "7702", the return type narrows to include an optional delegationAddress field — the smart
contract the EOA delegates to. When using mode: "4337", smartAccountAddress is the counterfactual smart
contract address (different from signer.address).
Provider Comparison
| Provider | 4337 | 7702 | External Wallets | Chain Restrictions | Key Feature |
|---|
| Alchemy | ✓ | ✓ | ✓ | Alchemy-supported chains | Modular accounts, gas policies |
| ZeroDev | ✓ | ✓ | ✓ | Any EVM chain | Kernel accounts, session keys, plugins |
| Pimlico | ✓ | ✓ | ✓ | Any EVM chain | Permissionless SDK, flexible paymaster |
| Biconomy | ✓ | ✓ | ✓ | MEE-supported chains | Cross-chain orchestration via MEE |
| Thirdweb | ✓ | ✓ | ✓ | Any EVM chain | Smart wallets, gas sponsorship |
| Gelato | | ✓ | | Any EVM chain | Native 7702, built-in gas sponsorship |
| Porto | | ✓ | | Multiple chains | 7702-native relay, merchant-based gas sponsorship |
| Safe | ✓ | | ✓ | Any EVM chain | Multi-sig, modular accounts |
| Rhinestone | ✓ | | ✓ | Any EVM chain | Cross-chain orchestration |
| Coinbase Developer Platform | ✓ | | | Base, Base Sepolia only | Coinbase smart accounts |
Provider Guides
Select a provider below for installation and usage instructions. Each tab shows two patterns:
- Custom Hook — a React component pattern that initializes the smart account once in a
useEffect and manages send state with useMutation from @tanstack/react-query. Good for screens that need reactive loading and error state out of the box.
- Action — the raw
async function call. Use this directly in event handlers, background tasks, or any state management setup you already have.
You’ll need an initialized and authenticated Para instance before calling any createXxxSmartAccount function. See the for details.
provides modular smart accounts with built-in gas sponsorship via Alchemy’s Gas Manager. Supports both EIP-4337 and EIP-7702 modes.Setup
-
Create an and obtain your API key and Gas Policy ID from the Alchemy dashboard.
-
Install the required dependencies:
npm install @getpara/react-native-wallet @getpara/aa-alchemy viem
Usage
Initializes the smart account once when the component mounts using useEffect, then wraps sendTransaction in a useMutation from React Query for built-in isPending and error state.import { useState, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { createAlchemySmartAccount } from "@getpara/aa-alchemy";
import { usePara } from "@getpara/react-native-wallet";
import type { SmartAccount } from "@getpara/react-native-wallet";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
export function AlchemyScreen() {
const para = usePara();
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
useEffect(() => {
createAlchemySmartAccount({
para,
apiKey: process.env.EXPO_PUBLIC_ALCHEMY_API_KEY!,
chain: sepolia,
gasPolicyId: process.env.EXPO_PUBLIC_ALCHEMY_GAS_POLICY_ID,
mode: "4337",
}).then(setSmartAccount);
}, []);
const { mutate: sendTx, isPending } = useMutation({
mutationFn: () =>
smartAccount!.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
}),
onSuccess: (receipt) =>
console.log("Transaction hash:", receipt.transactionHash),
});
return (
<View>
<Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
<Button
title={isPending ? "Sending..." : "Send"}
onPress={() => sendTx()}
disabled={!smartAccount || isPending}
/>
</View>
);
}
Directly awaits the smart account creation and calls sendTransaction as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.import { createAlchemySmartAccount } from "@getpara/aa-alchemy";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
const smartAccount = await createAlchemySmartAccount({
para,
apiKey: process.env.EXPO_PUBLIC_ALCHEMY_API_KEY!,
chain: sepolia,
gasPolicyId: process.env.EXPO_PUBLIC_ALCHEMY_GAS_POLICY_ID,
mode: "4337", // or "7702"
});
const receipt = await smartAccount.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
});
const batchReceipt = await smartAccount.sendBatchTransaction([
{ to: "0xRecipientA", value: parseEther("0.01") },
{ to: "0xContractAddress", data: "0xencodedCallData" },
]);
Alchemy requires chains from @account-kit/infra (e.g. sepolia, baseSepolia). Plain viem chains are automatically mapped if an Alchemy equivalent exists. For gasless transactions, set up a Gas Manager Policy in your and pass the policy ID as gasPolicyId.
provides Kernel smart accounts with gas sponsorship, session keys, recovery, and chain abstraction. Supports both EIP-4337 and EIP-7702 modes.Setup
-
Create a and obtain your Project ID from the ZeroDev dashboard.
-
Install the required dependencies:
npm install @getpara/react-native-wallet @getpara/aa-zerodev viem
Usage
Initializes the smart account once when the component mounts using useEffect, then wraps sendTransaction in a useMutation from React Query for built-in isPending and error state.import { useState, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { createZeroDevSmartAccount } from "@getpara/aa-zerodev";
import { usePara } from "@getpara/react-native-wallet";
import type { SmartAccount } from "@getpara/react-native-wallet";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
export function ZeroDevScreen() {
const para = usePara();
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
useEffect(() => {
createZeroDevSmartAccount({
para,
projectId: process.env.EXPO_PUBLIC_ZERODEV_PROJECT_ID!,
chain: sepolia,
mode: "4337",
}).then(setSmartAccount);
}, []);
const { mutate: sendTx, isPending } = useMutation({
mutationFn: () =>
smartAccount!.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
}),
onSuccess: (receipt) =>
console.log("Transaction hash:", receipt.transactionHash),
});
return (
<View>
<Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
<Button
title={isPending ? "Sending..." : "Send"}
onPress={() => sendTx()}
disabled={!smartAccount || isPending}
/>
</View>
);
}
Directly awaits the smart account creation and calls sendTransaction as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.import { createZeroDevSmartAccount } from "@getpara/aa-zerodev";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
const smartAccount = await createZeroDevSmartAccount({
para,
projectId: process.env.EXPO_PUBLIC_ZERODEV_PROJECT_ID!,
chain: sepolia,
mode: "4337", // or "7702"
});
const receipt = await smartAccount.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
});
const batchReceipt = await smartAccount.sendBatchTransaction([
{ to: "0xRecipientA", value: parseEther("0.01") },
{ to: "0xContractAddress", data: "0xencodedCallData" },
]);
You can optionally pass bundlerUrl and paymasterUrl to use custom infrastructure instead of ZeroDev’s defaults. See the for details.
provides AA infrastructure via permissionless.js, a lightweight TypeScript library built on viem. Supports both EIP-4337 and EIP-7702 modes.Setup
-
Create a and obtain your API key from the Pimlico dashboard.
-
Install the required dependencies:
npm install @getpara/react-native-wallet @getpara/aa-pimlico viem
Usage
Initializes the smart account once when the component mounts using useEffect, then wraps sendTransaction in a useMutation from React Query for built-in isPending and error state.import { useState, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { createPimlicoSmartAccount } from "@getpara/aa-pimlico";
import { usePara } from "@getpara/react-native-wallet";
import type { SmartAccount } from "@getpara/react-native-wallet";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
export function PimlicoScreen() {
const para = usePara();
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
useEffect(() => {
createPimlicoSmartAccount({
para,
apiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY!,
chain: sepolia,
mode: "4337",
}).then(setSmartAccount);
}, []);
const { mutate: sendTx, isPending } = useMutation({
mutationFn: () =>
smartAccount!.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
}),
onSuccess: (receipt) =>
console.log("Transaction hash:", receipt.transactionHash),
});
return (
<View>
<Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
<Button
title={isPending ? "Sending..." : "Send"}
onPress={() => sendTx()}
disabled={!smartAccount || isPending}
/>
</View>
);
}
Directly awaits the smart account creation and calls sendTransaction as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.import { createPimlicoSmartAccount } from "@getpara/aa-pimlico";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
const smartAccount = await createPimlicoSmartAccount({
para,
apiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY!,
chain: sepolia,
mode: "4337", // or "7702"
});
const receipt = await smartAccount.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
});
const batchReceipt = await smartAccount.sendBatchTransaction([
{ to: "0xRecipientA", value: parseEther("0.01") },
{ to: "0xContractAddress", data: "0xencodedCallData" },
]);
The Pimlico bundler/paymaster URL is automatically constructed from your API key and chain name. You can override it with a custom rpcUrl.
provides smart accounts with cross-chain orchestration via its Multi-chain Execution Environment (MEE). Supports both EIP-4337 and EIP-7702 modes.Setup
-
Create a and obtain your API key from the Biconomy dashboard.
-
Install the required dependencies:
npm install @getpara/react-native-wallet @getpara/aa-biconomy viem
Usage
Initializes the smart account once when the component mounts using useEffect, then wraps sendTransaction in a useMutation from React Query for built-in isPending and error state.import { useState, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { createBiconomySmartAccount } from "@getpara/aa-biconomy";
import { usePara } from "@getpara/react-native-wallet";
import type { SmartAccount } from "@getpara/react-native-wallet";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
export function BiconomyScreen() {
const para = usePara();
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
useEffect(() => {
createBiconomySmartAccount({
para,
apiKey: process.env.EXPO_PUBLIC_BICONOMY_API_KEY!,
chain: sepolia,
mode: "4337",
}).then(setSmartAccount);
}, []);
const { mutate: sendTx, isPending } = useMutation({
mutationFn: () =>
smartAccount!.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
}),
onSuccess: (receipt) =>
console.log("Transaction hash:", receipt.transactionHash),
});
return (
<View>
<Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
<Button
title={isPending ? "Sending..." : "Send"}
onPress={() => sendTx()}
disabled={!smartAccount || isPending}
/>
</View>
);
}
Directly awaits the smart account creation and calls sendTransaction as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.import { createBiconomySmartAccount } from "@getpara/aa-biconomy";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
const smartAccount = await createBiconomySmartAccount({
para,
apiKey: process.env.EXPO_PUBLIC_BICONOMY_API_KEY!,
chain: sepolia,
mode: "4337", // or "7702"
});
const receipt = await smartAccount.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
});
const batchReceipt = await smartAccount.sendBatchTransaction([
{ to: "0xRecipientA", value: parseEther("0.01") },
{ to: "0xContractAddress", data: "0xencodedCallData" },
]);
Biconomy transactions are executed via the MEE (Multi-chain Execution Environment). You can optionally pass a custom meeUrl to use your own MEE node.
provides smart wallets with built-in gas sponsorship. Supports both EIP-4337 and EIP-7702 modes.Setup
-
Create a and obtain your Client ID from the Thirdweb dashboard.
-
Install the required dependencies:
npm install @getpara/react-native-wallet @getpara/aa-thirdweb viem
Usage
Initializes the smart account once when the component mounts using useEffect, then wraps sendTransaction in a useMutation from React Query for built-in isPending and error state.import { useState, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { createThirdwebSmartAccount } from "@getpara/aa-thirdweb";
import { usePara } from "@getpara/react-native-wallet";
import type { SmartAccount } from "@getpara/react-native-wallet";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
export function ThirdwebScreen() {
const para = usePara();
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
useEffect(() => {
createThirdwebSmartAccount({
para,
clientId: process.env.EXPO_PUBLIC_THIRDWEB_CLIENT_ID!,
chain: sepolia,
sponsorGas: true,
mode: "4337",
}).then(setSmartAccount);
}, []);
const { mutate: sendTx, isPending } = useMutation({
mutationFn: () =>
smartAccount!.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
}),
onSuccess: (receipt) =>
console.log("Transaction hash:", receipt.transactionHash),
});
return (
<View>
<Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
<Button
title={isPending ? "Sending..." : "Send"}
onPress={() => sendTx()}
disabled={!smartAccount || isPending}
/>
</View>
);
}
Directly awaits the smart account creation and calls sendTransaction as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.import { createThirdwebSmartAccount } from "@getpara/aa-thirdweb";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
const smartAccount = await createThirdwebSmartAccount({
para,
clientId: process.env.EXPO_PUBLIC_THIRDWEB_CLIENT_ID!,
chain: sepolia,
sponsorGas: true,
mode: "4337", // or "7702"
});
const receipt = await smartAccount.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
});
const batchReceipt = await smartAccount.sendBatchTransaction([
{ to: "0xRecipientA", value: parseEther("0.01") },
{ to: "0xContractAddress", data: "0xencodedCallData" },
]);
Set sponsorGas: false to disable gas sponsorship. In EIP-4337 mode, you can optionally provide factoryAddress and accountAddress for custom smart wallet deployments.
provides native EIP-7702 smart accounts with built-in gas sponsorship via relay infrastructure. Gelato only supports EIP-7702 mode.Setup
-
Create a and obtain your API key from the Gelato dashboard.
-
Install the required dependencies:
npm install @getpara/react-native-wallet @getpara/aa-gelato viem
Usage
Initializes the smart account once when the component mounts using useEffect, then wraps sendTransaction in a useMutation from React Query for built-in isPending and error state.import { useState, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { createGelatoSmartAccount } from "@getpara/aa-gelato";
import { usePara } from "@getpara/react-native-wallet";
import type { SmartAccount } from "@getpara/react-native-wallet";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
export function GelatoScreen() {
const para = usePara();
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
useEffect(() => {
createGelatoSmartAccount({
para,
apiKey: process.env.EXPO_PUBLIC_GELATO_API_KEY!,
chain: sepolia,
}).then(setSmartAccount);
}, []);
const { mutate: sendTx, isPending } = useMutation({
mutationFn: () =>
smartAccount!.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
}),
onSuccess: (receipt) =>
console.log("Transaction hash:", receipt.transactionHash),
});
return (
<View>
<Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
<Button
title={isPending ? "Sending..." : "Send"}
onPress={() => sendTx()}
disabled={!smartAccount || isPending}
/>
</View>
);
}
Directly awaits the smart account creation and calls sendTransaction as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.import { createGelatoSmartAccount } from "@getpara/aa-gelato";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
const smartAccount = await createGelatoSmartAccount({
para,
apiKey: process.env.EXPO_PUBLIC_GELATO_API_KEY!,
chain: sepolia,
});
const receipt = await smartAccount.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
});
const batchReceipt = await smartAccount.sendBatchTransaction([
{ to: "0xRecipientA", value: parseEther("0.01") },
{ to: "0xContractAddress", data: "0xencodedCallData" },
]);
Gelato only supports EIP-7702 mode. Gas sponsorship is built into Gelato’s relay infrastructure — no separate paymaster configuration is needed.
provides 7702-native smart accounts with a built-in relay — no bundler or paymaster needed. Porto only supports EIP-7702 mode.Setup
-
No API key needed. Porto uses its own relay RPC. For mainnet gas sponsorship, set up a and pass your endpoint as
merchantUrl.
-
Install the required dependencies:
npm install @getpara/react-native-wallet @getpara/aa-porto viem
Usage
Initializes the smart account once when the component mounts using useEffect, then wraps sendTransaction in a useMutation from React Query for built-in isPending and error state.import { useState, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { createPortoSmartAccount } from "@getpara/aa-porto";
import { usePara } from "@getpara/react-native-wallet";
import type { SmartAccount } from "@getpara/react-native-wallet";
import { base } from "viem/chains";
import { parseEther } from "viem";
export function PortoScreen() {
const para = usePara();
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
useEffect(() => {
// Testnets: gas sponsored by default. Mainnet: merchantUrl required.
createPortoSmartAccount({
para,
chain: base,
merchantUrl: process.env.EXPO_PUBLIC_PORTO_MERCHANT_URL,
}).then(setSmartAccount);
}, []);
const { mutate: sendTx, isPending } = useMutation({
mutationFn: () =>
smartAccount!.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
}),
onSuccess: (receipt) =>
console.log("Transaction hash:", receipt.transactionHash),
});
return (
<View>
<Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
<Button
title={isPending ? "Sending..." : "Send"}
onPress={() => sendTx()}
disabled={!smartAccount || isPending}
/>
</View>
);
}
Directly awaits the smart account creation and calls sendTransaction as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.import { createPortoSmartAccount } from "@getpara/aa-porto";
import { parseEther } from "viem";
import { base } from "viem/chains";
// Testnets: gas sponsored by default. Mainnet: merchantUrl required.
const smartAccount = await createPortoSmartAccount({
para,
chain: base,
merchantUrl: process.env.EXPO_PUBLIC_PORTO_MERCHANT_URL,
});
const receipt = await smartAccount.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
});
const batchReceipt = await smartAccount.sendBatchTransaction([
{ to: "0xRecipientA", value: parseEther("0.01") },
{ to: "0xContractAddress", data: "0xencodedCallData" },
]);
Porto only supports EIP-7702 mode. Supports including Base, Optimism, Arbitrum, and Ethereum. On testnets, gas is sponsored by default. For mainnet, a is required.
provides multi-signature smart contract wallets with ERC-4337 compatibility, powered by Pimlico’s bundler and paymaster. Safe only supports EIP-4337 mode.Setup
-
Create a and obtain your API key — Safe uses Pimlico for bundler and paymaster services.
-
Install the required dependencies:
npm install @getpara/react-native-wallet @getpara/aa-safe viem
Usage
Initializes the smart account once when the component mounts using useEffect, then wraps sendTransaction in a useMutation from React Query for built-in isPending and error state.import { useState, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { createSafeSmartAccount } from "@getpara/aa-safe";
import { usePara } from "@getpara/react-native-wallet";
import type { SmartAccount } from "@getpara/react-native-wallet";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
export function SafeScreen() {
const para = usePara();
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
useEffect(() => {
createSafeSmartAccount({
para,
pimlicoApiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY!,
chain: sepolia,
}).then(setSmartAccount);
}, []);
const { mutate: sendTx, isPending } = useMutation({
mutationFn: () =>
smartAccount!.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
}),
onSuccess: (receipt) =>
console.log("Transaction hash:", receipt.transactionHash),
});
return (
<View>
<Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
<Button
title={isPending ? "Sending..." : "Send"}
onPress={() => sendTx()}
disabled={!smartAccount || isPending}
/>
</View>
);
}
Directly awaits the smart account creation and calls sendTransaction as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.import { createSafeSmartAccount } from "@getpara/aa-safe";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
const smartAccount = await createSafeSmartAccount({
para,
pimlicoApiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY!,
chain: sepolia,
});
const receipt = await smartAccount.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
});
const batchReceipt = await smartAccount.sendBatchTransaction([
{ to: "0xRecipientA", value: parseEther("0.01") },
{ to: "0xContractAddress", data: "0xencodedCallData" },
]);
Safe only supports EIP-4337 mode. You can optionally pass safeVersion (default: "1.4.1") and saltNonce for deterministic address generation.
provides cross-chain smart accounts with intent-based transactions and automatic bridging. Rhinestone only supports EIP-4337 mode.Setup
-
Obtain your Rhinestone API key and optionally a Pimlico API key for bundler/paymaster infrastructure.
-
Install the required dependencies:
npm install @getpara/react-native-wallet @getpara/aa-rhinestone viem
Usage
Initializes the smart account once when the component mounts using useEffect, then wraps sendTransaction in a useMutation from React Query for built-in isPending and error state.import { useState, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { createRhinestoneSmartAccount } from "@getpara/aa-rhinestone";
import { usePara } from "@getpara/react-native-wallet";
import type { SmartAccount } from "@getpara/react-native-wallet";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
export function RhinestoneScreen() {
const para = usePara();
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
useEffect(() => {
createRhinestoneSmartAccount({
para,
chain: sepolia,
rhinestoneApiKey: process.env.EXPO_PUBLIC_RHINESTONE_API_KEY!,
pimlicoApiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY,
}).then(setSmartAccount);
}, []);
const { mutate: sendTx, isPending } = useMutation({
mutationFn: () =>
smartAccount!.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
}),
onSuccess: (receipt) =>
console.log("Transaction hash:", receipt.transactionHash),
});
return (
<View>
<Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
<Button
title={isPending ? "Sending..." : "Send"}
onPress={() => sendTx()}
disabled={!smartAccount || isPending}
/>
</View>
);
}
Directly awaits the smart account creation and calls sendTransaction as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.import { createRhinestoneSmartAccount } from "@getpara/aa-rhinestone";
import { sepolia } from "viem/chains";
import { parseEther } from "viem";
const smartAccount = await createRhinestoneSmartAccount({
para,
chain: sepolia,
rhinestoneApiKey: process.env.EXPO_PUBLIC_RHINESTONE_API_KEY!,
pimlicoApiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY,
});
const receipt = await smartAccount.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
});
const batchReceipt = await smartAccount.sendBatchTransaction([
{ to: "0xRecipientA", value: parseEther("0.01") },
{ to: "0xContractAddress", data: "0xencodedCallData" },
]);
Rhinestone only supports EIP-4337 mode. Both rhinestoneApiKey and pimlicoApiKey are optional but recommended for production. See the for advanced cross-chain use cases.
provides Coinbase smart accounts on Base using viem’s built-in toCoinbaseSmartAccount. CDP only supports EIP-4337 mode on Base and Base Sepolia.Setup
-
Create a and obtain your RPC token from the paymaster URL in the CDP dashboard.
-
Install the required dependencies:
npm install @getpara/react-native-wallet @getpara/aa-cdp viem
Usage
Initializes the smart account once when the component mounts using useEffect, then wraps sendTransaction in a useMutation from React Query for built-in isPending and error state.import { useState, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { createCDPSmartAccount } from "@getpara/aa-cdp";
import { usePara } from "@getpara/react-native-wallet";
import type { SmartAccount } from "@getpara/react-native-wallet";
import { baseSepolia } from "viem/chains";
import { parseEther } from "viem";
export function CDPScreen() {
const para = usePara();
const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);
useEffect(() => {
createCDPSmartAccount({
para,
rpcToken: process.env.EXPO_PUBLIC_CDP_RPC_TOKEN!,
chain: baseSepolia,
}).then(setSmartAccount);
}, []);
const { mutate: sendTx, isPending } = useMutation({
mutationFn: () =>
smartAccount!.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
}),
onSuccess: (receipt) =>
console.log("Transaction hash:", receipt.transactionHash),
});
return (
<View>
<Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
<Button
title={isPending ? "Sending..." : "Send"}
onPress={() => sendTx()}
disabled={!smartAccount || isPending}
/>
</View>
);
}
Directly awaits the smart account creation and calls sendTransaction as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.import { createCDPSmartAccount } from "@getpara/aa-cdp";
import { baseSepolia } from "viem/chains";
import { parseEther } from "viem";
const smartAccount = await createCDPSmartAccount({
para,
rpcToken: process.env.EXPO_PUBLIC_CDP_RPC_TOKEN!,
chain: baseSepolia,
});
const receipt = await smartAccount.sendTransaction({
to: "0xRecipient",
value: parseEther("0.01"),
});
const batchReceipt = await smartAccount.sendBatchTransaction([
{ to: "0xRecipientA", value: parseEther("0.01") },
{ to: "0xContractAddress", data: "0xencodedCallData" },
]);
CDP only supports EIP-4337 mode and is limited to Base and Base Sepolia chains.
In EIP-4337 mode, funds must be sent to smartAccount.smartAccountAddress — not to the Para EOA address.
Key Considerations for Mobile
- Complete authentication with Para before the component mounts — the Para instance must have an active session
- The
useEffect pattern above fires once on mount; add config values to the dependency array if they can change at runtime
- Wrap
sendTransaction calls in useMutation for loading state and error handling in mobile UIs
- Test on physical devices to verify signing flows, particularly for EIP-7702 delegation transactions